react-native-nitro-storage 0.3.0 → 0.3.2
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/README.md +594 -247
- package/android/CMakeLists.txt +2 -0
- package/android/src/main/cpp/AndroidStorageAdapterCpp.cpp +102 -11
- package/android/src/main/cpp/AndroidStorageAdapterCpp.hpp +16 -0
- package/android/src/main/java/com/nitrostorage/AndroidStorageAdapter.kt +154 -34
- package/android/src/main/java/com/nitrostorage/NitroStoragePackage.kt +2 -2
- package/cpp/bindings/HybridStorage.cpp +176 -21
- package/cpp/bindings/HybridStorage.hpp +29 -2
- package/cpp/core/NativeStorageAdapter.hpp +16 -0
- package/ios/IOSStorageAdapterCpp.hpp +20 -0
- package/ios/IOSStorageAdapterCpp.mm +239 -32
- package/lib/commonjs/Storage.types.js +23 -1
- package/lib/commonjs/Storage.types.js.map +1 -1
- package/lib/commonjs/index.js +292 -75
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +473 -86
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/internal.js +10 -0
- package/lib/commonjs/internal.js.map +1 -1
- package/lib/commonjs/storage-hooks.js +36 -0
- package/lib/commonjs/storage-hooks.js.map +1 -0
- package/lib/module/Storage.types.js +22 -0
- package/lib/module/Storage.types.js.map +1 -1
- package/lib/module/index.js +264 -75
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +445 -86
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/internal.js +8 -0
- package/lib/module/internal.js.map +1 -1
- package/lib/module/storage-hooks.js +30 -0
- package/lib/module/storage-hooks.js.map +1 -0
- package/lib/typescript/Storage.nitro.d.ts +12 -0
- package/lib/typescript/Storage.nitro.d.ts.map +1 -1
- package/lib/typescript/Storage.types.d.ts +20 -0
- package/lib/typescript/Storage.types.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +33 -10
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/index.web.d.ts +45 -10
- package/lib/typescript/index.web.d.ts.map +1 -1
- package/lib/typescript/internal.d.ts +2 -0
- package/lib/typescript/internal.d.ts.map +1 -1
- package/lib/typescript/storage-hooks.d.ts +10 -0
- package/lib/typescript/storage-hooks.d.ts.map +1 -0
- package/nitrogen/generated/shared/c++/HybridStorageSpec.cpp +12 -0
- package/nitrogen/generated/shared/c++/HybridStorageSpec.hpp +12 -0
- package/package.json +8 -3
- package/src/Storage.nitro.ts +13 -2
- package/src/Storage.types.ts +22 -0
- package/src/index.ts +382 -123
- package/src/index.web.ts +618 -134
- package/src/internal.ts +14 -4
- package/src/migration.ts +1 -1
- package/src/storage-hooks.ts +48 -0
|
@@ -3,12 +3,25 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
Object.defineProperty(exports, "AccessControl", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _Storage.AccessControl;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "BiometricLevel", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () {
|
|
15
|
+
return _Storage.BiometricLevel;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
6
18
|
Object.defineProperty(exports, "StorageScope", {
|
|
7
19
|
enumerable: true,
|
|
8
20
|
get: function () {
|
|
9
21
|
return _Storage.StorageScope;
|
|
10
22
|
}
|
|
11
23
|
});
|
|
24
|
+
exports.createSecureAuthStorage = createSecureAuthStorage;
|
|
12
25
|
exports.createStorageItem = createStorageItem;
|
|
13
26
|
exports.getBatch = getBatch;
|
|
14
27
|
Object.defineProperty(exports, "migrateFromMMKV", {
|
|
@@ -23,13 +36,37 @@ exports.removeBatch = removeBatch;
|
|
|
23
36
|
exports.runTransaction = runTransaction;
|
|
24
37
|
exports.setBatch = setBatch;
|
|
25
38
|
exports.storage = void 0;
|
|
26
|
-
exports
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
39
|
+
Object.defineProperty(exports, "useSetStorage", {
|
|
40
|
+
enumerable: true,
|
|
41
|
+
get: function () {
|
|
42
|
+
return _storageHooks.useSetStorage;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
Object.defineProperty(exports, "useStorage", {
|
|
46
|
+
enumerable: true,
|
|
47
|
+
get: function () {
|
|
48
|
+
return _storageHooks.useStorage;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
Object.defineProperty(exports, "useStorageSelector", {
|
|
52
|
+
enumerable: true,
|
|
53
|
+
get: function () {
|
|
54
|
+
return _storageHooks.useStorageSelector;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
30
57
|
var _Storage = require("./Storage.types");
|
|
31
58
|
var _internal = require("./internal");
|
|
32
59
|
var _migration = require("./migration");
|
|
60
|
+
var _storageHooks = require("./storage-hooks");
|
|
61
|
+
function asInternal(item) {
|
|
62
|
+
return item;
|
|
63
|
+
}
|
|
64
|
+
function isUpdater(valueOrFn) {
|
|
65
|
+
return typeof valueOrFn === "function";
|
|
66
|
+
}
|
|
67
|
+
function typedKeys(record) {
|
|
68
|
+
return Object.keys(record);
|
|
69
|
+
}
|
|
33
70
|
const registeredMigrations = new Map();
|
|
34
71
|
const runMicrotask = typeof queueMicrotask === "function" ? queueMicrotask : task => {
|
|
35
72
|
Promise.resolve().then(task);
|
|
@@ -38,17 +75,71 @@ const memoryStore = new Map();
|
|
|
38
75
|
const memoryListeners = new Map();
|
|
39
76
|
const webScopeListeners = new Map([[_Storage.StorageScope.Disk, new Map()], [_Storage.StorageScope.Secure, new Map()]]);
|
|
40
77
|
const scopedRawCache = new Map([[_Storage.StorageScope.Disk, new Map()], [_Storage.StorageScope.Secure, new Map()]]);
|
|
78
|
+
const webScopeKeyIndex = new Map([[_Storage.StorageScope.Disk, new Set()], [_Storage.StorageScope.Secure, new Set()]]);
|
|
79
|
+
const hydratedWebScopeKeyIndex = new Set();
|
|
41
80
|
const pendingSecureWrites = new Map();
|
|
42
81
|
let secureFlushScheduled = false;
|
|
82
|
+
const SECURE_WEB_PREFIX = "__secure_";
|
|
83
|
+
const BIOMETRIC_WEB_PREFIX = "__bio_";
|
|
84
|
+
let hasWarnedAboutWebBiometricFallback = false;
|
|
43
85
|
function getBrowserStorage(scope) {
|
|
44
86
|
if (scope === _Storage.StorageScope.Disk) {
|
|
45
87
|
return globalThis.localStorage;
|
|
46
88
|
}
|
|
47
89
|
if (scope === _Storage.StorageScope.Secure) {
|
|
48
|
-
return globalThis.
|
|
90
|
+
return globalThis.localStorage;
|
|
49
91
|
}
|
|
50
92
|
return undefined;
|
|
51
93
|
}
|
|
94
|
+
function toSecureStorageKey(key) {
|
|
95
|
+
return `${SECURE_WEB_PREFIX}${key}`;
|
|
96
|
+
}
|
|
97
|
+
function fromSecureStorageKey(key) {
|
|
98
|
+
return key.slice(SECURE_WEB_PREFIX.length);
|
|
99
|
+
}
|
|
100
|
+
function toBiometricStorageKey(key) {
|
|
101
|
+
return `${BIOMETRIC_WEB_PREFIX}${key}`;
|
|
102
|
+
}
|
|
103
|
+
function fromBiometricStorageKey(key) {
|
|
104
|
+
return key.slice(BIOMETRIC_WEB_PREFIX.length);
|
|
105
|
+
}
|
|
106
|
+
function getWebScopeKeyIndex(scope) {
|
|
107
|
+
return webScopeKeyIndex.get(scope);
|
|
108
|
+
}
|
|
109
|
+
function hydrateWebScopeKeyIndex(scope) {
|
|
110
|
+
if (hydratedWebScopeKeyIndex.has(scope)) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const storage = getBrowserStorage(scope);
|
|
114
|
+
const keyIndex = getWebScopeKeyIndex(scope);
|
|
115
|
+
keyIndex.clear();
|
|
116
|
+
if (storage) {
|
|
117
|
+
for (let index = 0; index < storage.length; index += 1) {
|
|
118
|
+
const key = storage.key(index);
|
|
119
|
+
if (!key) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (scope === _Storage.StorageScope.Disk) {
|
|
123
|
+
if (!key.startsWith(SECURE_WEB_PREFIX) && !key.startsWith(BIOMETRIC_WEB_PREFIX)) {
|
|
124
|
+
keyIndex.add(key);
|
|
125
|
+
}
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (key.startsWith(SECURE_WEB_PREFIX)) {
|
|
129
|
+
keyIndex.add(fromSecureStorageKey(key));
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (key.startsWith(BIOMETRIC_WEB_PREFIX)) {
|
|
133
|
+
keyIndex.add(fromBiometricStorageKey(key));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
hydratedWebScopeKeyIndex.add(scope);
|
|
138
|
+
}
|
|
139
|
+
function ensureWebScopeKeyIndex(scope) {
|
|
140
|
+
hydrateWebScopeKeyIndex(scope);
|
|
141
|
+
return getWebScopeKeyIndex(scope);
|
|
142
|
+
}
|
|
52
143
|
function getScopedListeners(scope) {
|
|
53
144
|
return webScopeListeners.get(scope);
|
|
54
145
|
}
|
|
@@ -147,26 +238,65 @@ const WebStorage = {
|
|
|
147
238
|
dispose: () => {},
|
|
148
239
|
set: (key, value, scope) => {
|
|
149
240
|
const storage = getBrowserStorage(scope);
|
|
150
|
-
storage
|
|
241
|
+
if (!storage) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const storageKey = scope === _Storage.StorageScope.Secure ? toSecureStorageKey(key) : key;
|
|
245
|
+
storage.setItem(storageKey, value);
|
|
151
246
|
if (scope === _Storage.StorageScope.Disk || scope === _Storage.StorageScope.Secure) {
|
|
247
|
+
ensureWebScopeKeyIndex(scope).add(key);
|
|
152
248
|
notifyKeyListeners(getScopedListeners(scope), key);
|
|
153
249
|
}
|
|
154
250
|
},
|
|
155
251
|
get: (key, scope) => {
|
|
156
252
|
const storage = getBrowserStorage(scope);
|
|
157
|
-
|
|
253
|
+
const storageKey = scope === _Storage.StorageScope.Secure ? toSecureStorageKey(key) : key;
|
|
254
|
+
return storage?.getItem(storageKey) ?? undefined;
|
|
158
255
|
},
|
|
159
256
|
remove: (key, scope) => {
|
|
160
257
|
const storage = getBrowserStorage(scope);
|
|
161
|
-
storage
|
|
258
|
+
if (!storage) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
if (scope === _Storage.StorageScope.Secure) {
|
|
262
|
+
storage.removeItem(toSecureStorageKey(key));
|
|
263
|
+
storage.removeItem(toBiometricStorageKey(key));
|
|
264
|
+
} else {
|
|
265
|
+
storage.removeItem(key);
|
|
266
|
+
}
|
|
162
267
|
if (scope === _Storage.StorageScope.Disk || scope === _Storage.StorageScope.Secure) {
|
|
268
|
+
ensureWebScopeKeyIndex(scope).delete(key);
|
|
163
269
|
notifyKeyListeners(getScopedListeners(scope), key);
|
|
164
270
|
}
|
|
165
271
|
},
|
|
166
272
|
clear: scope => {
|
|
167
273
|
const storage = getBrowserStorage(scope);
|
|
168
|
-
storage
|
|
274
|
+
if (!storage) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
if (scope === _Storage.StorageScope.Secure) {
|
|
278
|
+
const keysToRemove = [];
|
|
279
|
+
for (let i = 0; i < storage.length; i++) {
|
|
280
|
+
const key = storage.key(i);
|
|
281
|
+
if (key?.startsWith(SECURE_WEB_PREFIX) || key?.startsWith(BIOMETRIC_WEB_PREFIX)) {
|
|
282
|
+
keysToRemove.push(key);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
keysToRemove.forEach(key => storage.removeItem(key));
|
|
286
|
+
} else if (scope === _Storage.StorageScope.Disk) {
|
|
287
|
+
const keysToRemove = [];
|
|
288
|
+
for (let i = 0; i < storage.length; i++) {
|
|
289
|
+
const key = storage.key(i);
|
|
290
|
+
if (key && !key.startsWith(SECURE_WEB_PREFIX) && !key.startsWith(BIOMETRIC_WEB_PREFIX)) {
|
|
291
|
+
keysToRemove.push(key);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
keysToRemove.forEach(key => storage.removeItem(key));
|
|
295
|
+
} else {
|
|
296
|
+
storage.clear();
|
|
297
|
+
}
|
|
169
298
|
if (scope === _Storage.StorageScope.Disk || scope === _Storage.StorageScope.Secure) {
|
|
299
|
+
ensureWebScopeKeyIndex(scope).clear();
|
|
170
300
|
notifyAllListeners(getScopedListeners(scope));
|
|
171
301
|
}
|
|
172
302
|
},
|
|
@@ -176,32 +306,129 @@ const WebStorage = {
|
|
|
176
306
|
return;
|
|
177
307
|
}
|
|
178
308
|
keys.forEach((key, index) => {
|
|
179
|
-
|
|
309
|
+
const value = values[index];
|
|
310
|
+
if (value === undefined) {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
const storageKey = scope === _Storage.StorageScope.Secure ? toSecureStorageKey(key) : key;
|
|
314
|
+
storage.setItem(storageKey, value);
|
|
180
315
|
});
|
|
181
316
|
if (scope === _Storage.StorageScope.Disk || scope === _Storage.StorageScope.Secure) {
|
|
317
|
+
const keyIndex = ensureWebScopeKeyIndex(scope);
|
|
318
|
+
keys.forEach(key => keyIndex.add(key));
|
|
182
319
|
const listeners = getScopedListeners(scope);
|
|
183
320
|
keys.forEach(key => notifyKeyListeners(listeners, key));
|
|
184
321
|
}
|
|
185
322
|
},
|
|
186
323
|
getBatch: (keys, scope) => {
|
|
187
324
|
const storage = getBrowserStorage(scope);
|
|
188
|
-
return keys.map(key =>
|
|
325
|
+
return keys.map(key => {
|
|
326
|
+
const storageKey = scope === _Storage.StorageScope.Secure ? toSecureStorageKey(key) : key;
|
|
327
|
+
return storage?.getItem(storageKey) ?? undefined;
|
|
328
|
+
});
|
|
189
329
|
},
|
|
190
330
|
removeBatch: (keys, scope) => {
|
|
191
331
|
const storage = getBrowserStorage(scope);
|
|
192
332
|
if (!storage) {
|
|
193
333
|
return;
|
|
194
334
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
335
|
+
if (scope === _Storage.StorageScope.Secure) {
|
|
336
|
+
keys.forEach(key => {
|
|
337
|
+
storage.removeItem(toSecureStorageKey(key));
|
|
338
|
+
storage.removeItem(toBiometricStorageKey(key));
|
|
339
|
+
});
|
|
340
|
+
} else {
|
|
341
|
+
keys.forEach(key => {
|
|
342
|
+
storage.removeItem(key);
|
|
343
|
+
});
|
|
344
|
+
}
|
|
198
345
|
if (scope === _Storage.StorageScope.Disk || scope === _Storage.StorageScope.Secure) {
|
|
346
|
+
const keyIndex = ensureWebScopeKeyIndex(scope);
|
|
347
|
+
keys.forEach(key => keyIndex.delete(key));
|
|
199
348
|
const listeners = getScopedListeners(scope);
|
|
200
349
|
keys.forEach(key => notifyKeyListeners(listeners, key));
|
|
201
350
|
}
|
|
202
351
|
},
|
|
352
|
+
removeByPrefix: (prefix, scope) => {
|
|
353
|
+
if (scope !== _Storage.StorageScope.Disk && scope !== _Storage.StorageScope.Secure) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
const keyIndex = ensureWebScopeKeyIndex(scope);
|
|
357
|
+
const keys = Array.from(keyIndex).filter(key => key.startsWith(prefix));
|
|
358
|
+
if (keys.length === 0) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
WebStorage.removeBatch(keys, scope);
|
|
362
|
+
},
|
|
203
363
|
addOnChange: (_scope, _callback) => {
|
|
204
364
|
return () => {};
|
|
365
|
+
},
|
|
366
|
+
has: (key, scope) => {
|
|
367
|
+
const storage = getBrowserStorage(scope);
|
|
368
|
+
if (scope === _Storage.StorageScope.Secure) {
|
|
369
|
+
return storage?.getItem(toSecureStorageKey(key)) !== null || storage?.getItem(toBiometricStorageKey(key)) !== null;
|
|
370
|
+
}
|
|
371
|
+
return storage?.getItem(key) !== null;
|
|
372
|
+
},
|
|
373
|
+
getAllKeys: scope => {
|
|
374
|
+
if (scope !== _Storage.StorageScope.Disk && scope !== _Storage.StorageScope.Secure) {
|
|
375
|
+
return [];
|
|
376
|
+
}
|
|
377
|
+
return Array.from(ensureWebScopeKeyIndex(scope));
|
|
378
|
+
},
|
|
379
|
+
size: scope => {
|
|
380
|
+
if (scope === _Storage.StorageScope.Disk || scope === _Storage.StorageScope.Secure) {
|
|
381
|
+
return ensureWebScopeKeyIndex(scope).size;
|
|
382
|
+
}
|
|
383
|
+
return 0;
|
|
384
|
+
},
|
|
385
|
+
setSecureAccessControl: () => {},
|
|
386
|
+
setSecureWritesAsync: _enabled => {},
|
|
387
|
+
setKeychainAccessGroup: () => {},
|
|
388
|
+
setSecureBiometric: (key, value) => {
|
|
389
|
+
if (typeof __DEV__ !== "undefined" && __DEV__ && !hasWarnedAboutWebBiometricFallback) {
|
|
390
|
+
hasWarnedAboutWebBiometricFallback = true;
|
|
391
|
+
console.warn("[NitroStorage] Biometric storage is not supported on web. Using localStorage.");
|
|
392
|
+
}
|
|
393
|
+
globalThis.localStorage?.setItem(toBiometricStorageKey(key), value);
|
|
394
|
+
ensureWebScopeKeyIndex(_Storage.StorageScope.Secure).add(key);
|
|
395
|
+
notifyKeyListeners(getScopedListeners(_Storage.StorageScope.Secure), key);
|
|
396
|
+
},
|
|
397
|
+
getSecureBiometric: key => {
|
|
398
|
+
return globalThis.localStorage?.getItem(toBiometricStorageKey(key)) ?? undefined;
|
|
399
|
+
},
|
|
400
|
+
deleteSecureBiometric: key => {
|
|
401
|
+
const storage = globalThis.localStorage;
|
|
402
|
+
storage?.removeItem(toBiometricStorageKey(key));
|
|
403
|
+
if (storage?.getItem(toSecureStorageKey(key)) === null) {
|
|
404
|
+
ensureWebScopeKeyIndex(_Storage.StorageScope.Secure).delete(key);
|
|
405
|
+
}
|
|
406
|
+
notifyKeyListeners(getScopedListeners(_Storage.StorageScope.Secure), key);
|
|
407
|
+
},
|
|
408
|
+
hasSecureBiometric: key => {
|
|
409
|
+
return globalThis.localStorage?.getItem(toBiometricStorageKey(key)) !== null;
|
|
410
|
+
},
|
|
411
|
+
clearSecureBiometric: () => {
|
|
412
|
+
const storage = globalThis.localStorage;
|
|
413
|
+
if (!storage) return;
|
|
414
|
+
const keysToNotify = [];
|
|
415
|
+
const toRemove = [];
|
|
416
|
+
for (let i = 0; i < storage.length; i++) {
|
|
417
|
+
const k = storage.key(i);
|
|
418
|
+
if (k?.startsWith(BIOMETRIC_WEB_PREFIX)) {
|
|
419
|
+
toRemove.push(k);
|
|
420
|
+
keysToNotify.push(fromBiometricStorageKey(k));
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
toRemove.forEach(k => storage.removeItem(k));
|
|
424
|
+
const keyIndex = ensureWebScopeKeyIndex(_Storage.StorageScope.Secure);
|
|
425
|
+
keysToNotify.forEach(key => {
|
|
426
|
+
if (storage.getItem(toSecureStorageKey(key)) === null) {
|
|
427
|
+
keyIndex.delete(key);
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
const listeners = getScopedListeners(_Storage.StorageScope.Secure);
|
|
431
|
+
keysToNotify.forEach(key => notifyKeyListeners(listeners, key));
|
|
205
432
|
}
|
|
206
433
|
};
|
|
207
434
|
function getRawValue(key, scope) {
|
|
@@ -272,10 +499,71 @@ const storage = exports.storage = {
|
|
|
272
499
|
storage.clear(_Storage.StorageScope.Memory);
|
|
273
500
|
storage.clear(_Storage.StorageScope.Disk);
|
|
274
501
|
storage.clear(_Storage.StorageScope.Secure);
|
|
275
|
-
}
|
|
502
|
+
},
|
|
503
|
+
clearNamespace: (namespace, scope) => {
|
|
504
|
+
(0, _internal.assertValidScope)(scope);
|
|
505
|
+
if (scope === _Storage.StorageScope.Memory) {
|
|
506
|
+
for (const key of memoryStore.keys()) {
|
|
507
|
+
if ((0, _internal.isNamespaced)(key, namespace)) {
|
|
508
|
+
memoryStore.delete(key);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
notifyAllListeners(memoryListeners);
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
const keyPrefix = (0, _internal.prefixKey)(namespace, "");
|
|
515
|
+
if (scope === _Storage.StorageScope.Secure) {
|
|
516
|
+
flushSecureWrites();
|
|
517
|
+
}
|
|
518
|
+
clearScopeRawCache(scope);
|
|
519
|
+
WebStorage.removeByPrefix(keyPrefix, scope);
|
|
520
|
+
},
|
|
521
|
+
clearBiometric: () => {
|
|
522
|
+
WebStorage.clearSecureBiometric();
|
|
523
|
+
},
|
|
524
|
+
has: (key, scope) => {
|
|
525
|
+
(0, _internal.assertValidScope)(scope);
|
|
526
|
+
if (scope === _Storage.StorageScope.Memory) return memoryStore.has(key);
|
|
527
|
+
return WebStorage.has(key, scope);
|
|
528
|
+
},
|
|
529
|
+
getAllKeys: scope => {
|
|
530
|
+
(0, _internal.assertValidScope)(scope);
|
|
531
|
+
if (scope === _Storage.StorageScope.Memory) return Array.from(memoryStore.keys());
|
|
532
|
+
return WebStorage.getAllKeys(scope);
|
|
533
|
+
},
|
|
534
|
+
getAll: scope => {
|
|
535
|
+
(0, _internal.assertValidScope)(scope);
|
|
536
|
+
const result = {};
|
|
537
|
+
if (scope === _Storage.StorageScope.Memory) {
|
|
538
|
+
memoryStore.forEach((value, key) => {
|
|
539
|
+
if (typeof value === "string") result[key] = value;
|
|
540
|
+
});
|
|
541
|
+
return result;
|
|
542
|
+
}
|
|
543
|
+
const keys = WebStorage.getAllKeys(scope);
|
|
544
|
+
keys.forEach(key => {
|
|
545
|
+
const val = WebStorage.get(key, scope);
|
|
546
|
+
if (val !== undefined) result[key] = val;
|
|
547
|
+
});
|
|
548
|
+
return result;
|
|
549
|
+
},
|
|
550
|
+
size: scope => {
|
|
551
|
+
(0, _internal.assertValidScope)(scope);
|
|
552
|
+
if (scope === _Storage.StorageScope.Memory) return memoryStore.size;
|
|
553
|
+
return WebStorage.size(scope);
|
|
554
|
+
},
|
|
555
|
+
setAccessControl: _level => {},
|
|
556
|
+
setSecureWritesAsync: _enabled => {},
|
|
557
|
+
flushSecureWrites: () => {
|
|
558
|
+
flushSecureWrites();
|
|
559
|
+
},
|
|
560
|
+
setKeychainAccessGroup: _group => {}
|
|
276
561
|
};
|
|
277
562
|
function canUseRawBatchPath(item) {
|
|
278
|
-
return item._hasExpiration === false && item._hasValidation === false;
|
|
563
|
+
return item._hasExpiration === false && item._hasValidation === false && item._isBiometric !== true && item._secureAccessControl === undefined;
|
|
564
|
+
}
|
|
565
|
+
function canUseSecureRawBatchPath(item) {
|
|
566
|
+
return item._hasExpiration === false && item._hasValidation === false && item._isBiometric !== true;
|
|
279
567
|
}
|
|
280
568
|
function defaultSerialize(value) {
|
|
281
569
|
return (0, _internal.serializeWithPrimitiveFastPath)(value);
|
|
@@ -284,16 +572,21 @@ function defaultDeserialize(value) {
|
|
|
284
572
|
return (0, _internal.deserializeWithPrimitiveFastPath)(value);
|
|
285
573
|
}
|
|
286
574
|
function createStorageItem(config) {
|
|
575
|
+
const storageKey = (0, _internal.prefixKey)(config.namespace, config.key);
|
|
287
576
|
const serialize = config.serialize ?? defaultSerialize;
|
|
288
577
|
const deserialize = config.deserialize ?? defaultDeserialize;
|
|
289
578
|
const isMemory = config.scope === _Storage.StorageScope.Memory;
|
|
579
|
+
const isBiometric = config.biometric === true && config.scope === _Storage.StorageScope.Secure;
|
|
580
|
+
const secureAccessControl = config.accessControl;
|
|
290
581
|
const validate = config.validate;
|
|
291
582
|
const onValidationError = config.onValidationError;
|
|
292
583
|
const expiration = config.expiration;
|
|
584
|
+
const onExpired = config.onExpired;
|
|
293
585
|
const expirationTtlMs = expiration?.ttlMs;
|
|
294
586
|
const memoryExpiration = expiration && isMemory ? new Map() : null;
|
|
295
587
|
const readCache = !isMemory && config.readCache === true;
|
|
296
|
-
const coalesceSecureWrites = config.scope === _Storage.StorageScope.Secure && config.coalesceSecureWrites === true;
|
|
588
|
+
const coalesceSecureWrites = config.scope === _Storage.StorageScope.Secure && config.coalesceSecureWrites === true && !isBiometric && secureAccessControl === undefined;
|
|
589
|
+
const defaultValue = config.defaultValue;
|
|
297
590
|
const nonMemoryScope = config.scope === _Storage.StorageScope.Disk ? _Storage.StorageScope.Disk : config.scope === _Storage.StorageScope.Secure ? _Storage.StorageScope.Secure : null;
|
|
298
591
|
if (expiration && expiration.ttlMs <= 0) {
|
|
299
592
|
throw new Error("expiration.ttlMs must be greater than 0.");
|
|
@@ -303,10 +596,12 @@ function createStorageItem(config) {
|
|
|
303
596
|
let lastRaw = undefined;
|
|
304
597
|
let lastValue;
|
|
305
598
|
let hasLastValue = false;
|
|
599
|
+
let lastExpiresAt = undefined;
|
|
306
600
|
const invalidateParsedCache = () => {
|
|
307
601
|
lastRaw = undefined;
|
|
308
602
|
lastValue = undefined;
|
|
309
603
|
hasLastValue = false;
|
|
604
|
+
lastExpiresAt = undefined;
|
|
310
605
|
};
|
|
311
606
|
const ensureSubscription = () => {
|
|
312
607
|
if (unsubscribe) {
|
|
@@ -317,65 +612,77 @@ function createStorageItem(config) {
|
|
|
317
612
|
listeners.forEach(callback => callback());
|
|
318
613
|
};
|
|
319
614
|
if (isMemory) {
|
|
320
|
-
unsubscribe = addKeyListener(memoryListeners,
|
|
615
|
+
unsubscribe = addKeyListener(memoryListeners, storageKey, listener);
|
|
321
616
|
return;
|
|
322
617
|
}
|
|
323
|
-
unsubscribe = addKeyListener(getScopedListeners(nonMemoryScope),
|
|
618
|
+
unsubscribe = addKeyListener(getScopedListeners(nonMemoryScope), storageKey, listener);
|
|
324
619
|
};
|
|
325
620
|
const readStoredRaw = () => {
|
|
326
621
|
if (isMemory) {
|
|
327
622
|
if (memoryExpiration) {
|
|
328
|
-
const expiresAt = memoryExpiration.get(
|
|
623
|
+
const expiresAt = memoryExpiration.get(storageKey);
|
|
329
624
|
if (expiresAt !== undefined && expiresAt <= Date.now()) {
|
|
330
|
-
memoryExpiration.delete(
|
|
331
|
-
memoryStore.delete(
|
|
332
|
-
notifyKeyListeners(memoryListeners,
|
|
625
|
+
memoryExpiration.delete(storageKey);
|
|
626
|
+
memoryStore.delete(storageKey);
|
|
627
|
+
notifyKeyListeners(memoryListeners, storageKey);
|
|
628
|
+
onExpired?.(storageKey);
|
|
333
629
|
return undefined;
|
|
334
630
|
}
|
|
335
631
|
}
|
|
336
|
-
return memoryStore.get(
|
|
632
|
+
return memoryStore.get(storageKey);
|
|
337
633
|
}
|
|
338
|
-
if (nonMemoryScope === _Storage.StorageScope.Secure && hasPendingSecureWrite(
|
|
339
|
-
return readPendingSecureWrite(
|
|
634
|
+
if (nonMemoryScope === _Storage.StorageScope.Secure && !isBiometric && hasPendingSecureWrite(storageKey)) {
|
|
635
|
+
return readPendingSecureWrite(storageKey);
|
|
340
636
|
}
|
|
341
637
|
if (readCache) {
|
|
342
|
-
if (hasCachedRawValue(nonMemoryScope,
|
|
343
|
-
return readCachedRawValue(nonMemoryScope,
|
|
638
|
+
if (hasCachedRawValue(nonMemoryScope, storageKey)) {
|
|
639
|
+
return readCachedRawValue(nonMemoryScope, storageKey);
|
|
344
640
|
}
|
|
345
641
|
}
|
|
346
|
-
|
|
347
|
-
|
|
642
|
+
if (isBiometric) {
|
|
643
|
+
return WebStorage.getSecureBiometric(storageKey);
|
|
644
|
+
}
|
|
645
|
+
const raw = WebStorage.get(storageKey, config.scope);
|
|
646
|
+
cacheRawValue(nonMemoryScope, storageKey, raw);
|
|
348
647
|
return raw;
|
|
349
648
|
};
|
|
350
649
|
const writeStoredRaw = rawValue => {
|
|
351
|
-
|
|
650
|
+
if (isBiometric) {
|
|
651
|
+
WebStorage.setSecureBiometric(storageKey, rawValue);
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
cacheRawValue(nonMemoryScope, storageKey, rawValue);
|
|
352
655
|
if (coalesceSecureWrites) {
|
|
353
|
-
scheduleSecureWrite(
|
|
656
|
+
scheduleSecureWrite(storageKey, rawValue);
|
|
354
657
|
return;
|
|
355
658
|
}
|
|
356
659
|
if (nonMemoryScope === _Storage.StorageScope.Secure) {
|
|
357
|
-
clearPendingSecureWrite(
|
|
660
|
+
clearPendingSecureWrite(storageKey);
|
|
358
661
|
}
|
|
359
|
-
WebStorage.set(
|
|
662
|
+
WebStorage.set(storageKey, rawValue, config.scope);
|
|
360
663
|
};
|
|
361
664
|
const removeStoredRaw = () => {
|
|
362
|
-
|
|
665
|
+
if (isBiometric) {
|
|
666
|
+
WebStorage.deleteSecureBiometric(storageKey);
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
cacheRawValue(nonMemoryScope, storageKey, undefined);
|
|
363
670
|
if (coalesceSecureWrites) {
|
|
364
|
-
scheduleSecureWrite(
|
|
671
|
+
scheduleSecureWrite(storageKey, undefined);
|
|
365
672
|
return;
|
|
366
673
|
}
|
|
367
674
|
if (nonMemoryScope === _Storage.StorageScope.Secure) {
|
|
368
|
-
clearPendingSecureWrite(
|
|
675
|
+
clearPendingSecureWrite(storageKey);
|
|
369
676
|
}
|
|
370
|
-
WebStorage.remove(
|
|
677
|
+
WebStorage.remove(storageKey, config.scope);
|
|
371
678
|
};
|
|
372
679
|
const writeValueWithoutValidation = value => {
|
|
373
680
|
if (isMemory) {
|
|
374
681
|
if (memoryExpiration) {
|
|
375
|
-
memoryExpiration.set(
|
|
682
|
+
memoryExpiration.set(storageKey, Date.now() + (expirationTtlMs ?? 0));
|
|
376
683
|
}
|
|
377
|
-
memoryStore.set(
|
|
378
|
-
notifyKeyListeners(memoryListeners,
|
|
684
|
+
memoryStore.set(storageKey, value);
|
|
685
|
+
notifyKeyListeners(memoryListeners, storageKey);
|
|
379
686
|
return;
|
|
380
687
|
}
|
|
381
688
|
const serialized = serialize(value);
|
|
@@ -394,7 +701,7 @@ function createStorageItem(config) {
|
|
|
394
701
|
if (onValidationError) {
|
|
395
702
|
return onValidationError(invalidValue);
|
|
396
703
|
}
|
|
397
|
-
return
|
|
704
|
+
return defaultValue;
|
|
398
705
|
};
|
|
399
706
|
const ensureValidatedValue = (candidate, hadStoredValue) => {
|
|
400
707
|
if (!validate || validate(candidate)) {
|
|
@@ -402,7 +709,7 @@ function createStorageItem(config) {
|
|
|
402
709
|
}
|
|
403
710
|
const resolved = resolveInvalidValue(candidate);
|
|
404
711
|
if (validate && !validate(resolved)) {
|
|
405
|
-
return
|
|
712
|
+
return defaultValue;
|
|
406
713
|
}
|
|
407
714
|
if (hadStoredValue) {
|
|
408
715
|
writeValueWithoutValidation(resolved);
|
|
@@ -411,30 +718,53 @@ function createStorageItem(config) {
|
|
|
411
718
|
};
|
|
412
719
|
const get = () => {
|
|
413
720
|
const raw = readStoredRaw();
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
721
|
+
if (!memoryExpiration && raw === lastRaw && hasLastValue) {
|
|
722
|
+
if (!expiration || lastExpiresAt === null) {
|
|
723
|
+
return lastValue;
|
|
724
|
+
}
|
|
725
|
+
if (typeof lastExpiresAt === "number") {
|
|
726
|
+
if (lastExpiresAt > Date.now()) {
|
|
727
|
+
return lastValue;
|
|
728
|
+
}
|
|
729
|
+
removeStoredRaw();
|
|
730
|
+
invalidateParsedCache();
|
|
731
|
+
onExpired?.(storageKey);
|
|
732
|
+
lastValue = ensureValidatedValue(defaultValue, false);
|
|
733
|
+
hasLastValue = true;
|
|
734
|
+
return lastValue;
|
|
735
|
+
}
|
|
417
736
|
}
|
|
418
737
|
lastRaw = raw;
|
|
419
738
|
if (raw === undefined) {
|
|
420
|
-
|
|
739
|
+
lastExpiresAt = undefined;
|
|
740
|
+
lastValue = ensureValidatedValue(defaultValue, false);
|
|
421
741
|
hasLastValue = true;
|
|
422
742
|
return lastValue;
|
|
423
743
|
}
|
|
424
744
|
if (isMemory) {
|
|
745
|
+
lastExpiresAt = undefined;
|
|
425
746
|
lastValue = ensureValidatedValue(raw, true);
|
|
426
747
|
hasLastValue = true;
|
|
427
748
|
return lastValue;
|
|
428
749
|
}
|
|
750
|
+
if (typeof raw !== "string") {
|
|
751
|
+
lastExpiresAt = undefined;
|
|
752
|
+
lastValue = ensureValidatedValue(defaultValue, false);
|
|
753
|
+
hasLastValue = true;
|
|
754
|
+
return lastValue;
|
|
755
|
+
}
|
|
429
756
|
let deserializableRaw = raw;
|
|
430
757
|
if (expiration) {
|
|
758
|
+
let envelopeExpiresAt = null;
|
|
431
759
|
try {
|
|
432
760
|
const parsed = JSON.parse(raw);
|
|
433
761
|
if ((0, _internal.isStoredEnvelope)(parsed)) {
|
|
762
|
+
envelopeExpiresAt = parsed.expiresAt;
|
|
434
763
|
if (parsed.expiresAt <= Date.now()) {
|
|
435
764
|
removeStoredRaw();
|
|
436
765
|
invalidateParsedCache();
|
|
437
|
-
|
|
766
|
+
onExpired?.(storageKey);
|
|
767
|
+
lastValue = ensureValidatedValue(defaultValue, false);
|
|
438
768
|
hasLastValue = true;
|
|
439
769
|
return lastValue;
|
|
440
770
|
}
|
|
@@ -443,17 +773,19 @@ function createStorageItem(config) {
|
|
|
443
773
|
} catch {
|
|
444
774
|
// Keep backward compatibility with legacy raw values.
|
|
445
775
|
}
|
|
776
|
+
lastExpiresAt = envelopeExpiresAt;
|
|
777
|
+
} else {
|
|
778
|
+
lastExpiresAt = undefined;
|
|
446
779
|
}
|
|
447
780
|
lastValue = ensureValidatedValue(deserialize(deserializableRaw), true);
|
|
448
781
|
hasLastValue = true;
|
|
449
782
|
return lastValue;
|
|
450
783
|
};
|
|
451
784
|
const set = valueOrFn => {
|
|
452
|
-
const
|
|
453
|
-
const newValue = typeof valueOrFn === "function" ? valueOrFn(currentValue) : valueOrFn;
|
|
785
|
+
const newValue = isUpdater(valueOrFn) ? valueOrFn(get()) : valueOrFn;
|
|
454
786
|
invalidateParsedCache();
|
|
455
787
|
if (validate && !validate(newValue)) {
|
|
456
|
-
throw new Error(`Validation failed for key "${
|
|
788
|
+
throw new Error(`Validation failed for key "${storageKey}" in scope "${_Storage.StorageScope[config.scope]}".`);
|
|
457
789
|
}
|
|
458
790
|
writeValueWithoutValidation(newValue);
|
|
459
791
|
};
|
|
@@ -461,14 +793,19 @@ function createStorageItem(config) {
|
|
|
461
793
|
invalidateParsedCache();
|
|
462
794
|
if (isMemory) {
|
|
463
795
|
if (memoryExpiration) {
|
|
464
|
-
memoryExpiration.delete(
|
|
796
|
+
memoryExpiration.delete(storageKey);
|
|
465
797
|
}
|
|
466
|
-
memoryStore.delete(
|
|
467
|
-
notifyKeyListeners(memoryListeners,
|
|
798
|
+
memoryStore.delete(storageKey);
|
|
799
|
+
notifyKeyListeners(memoryListeners, storageKey);
|
|
468
800
|
return;
|
|
469
801
|
}
|
|
470
802
|
removeStoredRaw();
|
|
471
803
|
};
|
|
804
|
+
const hasItem = () => {
|
|
805
|
+
if (isMemory) return memoryStore.has(storageKey);
|
|
806
|
+
if (isBiometric) return WebStorage.hasSecureBiometric(storageKey);
|
|
807
|
+
return WebStorage.has(storageKey, config.scope);
|
|
808
|
+
};
|
|
472
809
|
const subscribe = callback => {
|
|
473
810
|
ensureSubscription();
|
|
474
811
|
listeners.add(callback);
|
|
@@ -484,6 +821,7 @@ function createStorageItem(config) {
|
|
|
484
821
|
get,
|
|
485
822
|
set,
|
|
486
823
|
delete: deleteItem,
|
|
824
|
+
has: hasItem,
|
|
487
825
|
subscribe,
|
|
488
826
|
serialize,
|
|
489
827
|
deserialize,
|
|
@@ -494,43 +832,21 @@ function createStorageItem(config) {
|
|
|
494
832
|
_hasValidation: validate !== undefined,
|
|
495
833
|
_hasExpiration: expiration !== undefined,
|
|
496
834
|
_readCacheEnabled: readCache,
|
|
835
|
+
_isBiometric: isBiometric,
|
|
836
|
+
...(secureAccessControl !== undefined ? {
|
|
837
|
+
_secureAccessControl: secureAccessControl
|
|
838
|
+
} : {}),
|
|
497
839
|
scope: config.scope,
|
|
498
|
-
key:
|
|
840
|
+
key: storageKey
|
|
499
841
|
};
|
|
500
842
|
return storageItem;
|
|
501
843
|
}
|
|
502
|
-
function useStorage(item) {
|
|
503
|
-
const value = (0, _react.useSyncExternalStore)(item.subscribe, item.get, item.get);
|
|
504
|
-
return [value, item.set];
|
|
505
|
-
}
|
|
506
|
-
function useStorageSelector(item, selector, isEqual = Object.is) {
|
|
507
|
-
const selectedRef = (0, _react.useRef)({
|
|
508
|
-
hasValue: false
|
|
509
|
-
});
|
|
510
|
-
const getSelectedSnapshot = () => {
|
|
511
|
-
const nextSelected = selector(item.get());
|
|
512
|
-
const current = selectedRef.current;
|
|
513
|
-
if (current.hasValue && isEqual(current.value, nextSelected)) {
|
|
514
|
-
return current.value;
|
|
515
|
-
}
|
|
516
|
-
selectedRef.current = {
|
|
517
|
-
hasValue: true,
|
|
518
|
-
value: nextSelected
|
|
519
|
-
};
|
|
520
|
-
return nextSelected;
|
|
521
|
-
};
|
|
522
|
-
const selectedValue = (0, _react.useSyncExternalStore)(item.subscribe, getSelectedSnapshot, getSelectedSnapshot);
|
|
523
|
-
return [selectedValue, item.set];
|
|
524
|
-
}
|
|
525
|
-
function useSetStorage(item) {
|
|
526
|
-
return item.set;
|
|
527
|
-
}
|
|
528
844
|
function getBatch(items, scope) {
|
|
529
845
|
(0, _internal.assertBatchScope)(items, scope);
|
|
530
846
|
if (scope === _Storage.StorageScope.Memory) {
|
|
531
847
|
return items.map(item => item.get());
|
|
532
848
|
}
|
|
533
|
-
const useRawBatchPath = items.every(item => canUseRawBatchPath(item));
|
|
849
|
+
const useRawBatchPath = items.every(item => scope === _Storage.StorageScope.Secure ? canUseSecureRawBatchPath(item) : canUseRawBatchPath(item));
|
|
534
850
|
if (!useRawBatchPath) {
|
|
535
851
|
return items.map(item => item.get());
|
|
536
852
|
}
|
|
@@ -559,6 +875,9 @@ function getBatch(items, scope) {
|
|
|
559
875
|
fetchedValues.forEach((value, index) => {
|
|
560
876
|
const key = keysToFetch[index];
|
|
561
877
|
const targetIndex = keyIndexes[index];
|
|
878
|
+
if (key === undefined || targetIndex === undefined) {
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
562
881
|
rawValues[targetIndex] = value;
|
|
563
882
|
cacheRawValue(scope, key, value);
|
|
564
883
|
});
|
|
@@ -580,9 +899,54 @@ function setBatch(items, scope) {
|
|
|
580
899
|
}) => item.set(value));
|
|
581
900
|
return;
|
|
582
901
|
}
|
|
902
|
+
if (scope === _Storage.StorageScope.Secure) {
|
|
903
|
+
const secureEntries = items.map(({
|
|
904
|
+
item,
|
|
905
|
+
value
|
|
906
|
+
}) => ({
|
|
907
|
+
item,
|
|
908
|
+
value,
|
|
909
|
+
internal: asInternal(item)
|
|
910
|
+
}));
|
|
911
|
+
const canUseSecureBatchPath = secureEntries.every(({
|
|
912
|
+
internal
|
|
913
|
+
}) => canUseSecureRawBatchPath(internal));
|
|
914
|
+
if (!canUseSecureBatchPath) {
|
|
915
|
+
items.forEach(({
|
|
916
|
+
item,
|
|
917
|
+
value
|
|
918
|
+
}) => item.set(value));
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
flushSecureWrites();
|
|
922
|
+
const groupedByAccessControl = new Map();
|
|
923
|
+
secureEntries.forEach(({
|
|
924
|
+
item,
|
|
925
|
+
value,
|
|
926
|
+
internal
|
|
927
|
+
}) => {
|
|
928
|
+
const accessControl = internal._secureAccessControl ?? _Storage.AccessControl.WhenUnlocked;
|
|
929
|
+
const existingGroup = groupedByAccessControl.get(accessControl);
|
|
930
|
+
const group = existingGroup ?? {
|
|
931
|
+
keys: [],
|
|
932
|
+
values: []
|
|
933
|
+
};
|
|
934
|
+
group.keys.push(item.key);
|
|
935
|
+
group.values.push(item.serialize(value));
|
|
936
|
+
if (!existingGroup) {
|
|
937
|
+
groupedByAccessControl.set(accessControl, group);
|
|
938
|
+
}
|
|
939
|
+
});
|
|
940
|
+
groupedByAccessControl.forEach((group, accessControl) => {
|
|
941
|
+
WebStorage.setSecureAccessControl(accessControl);
|
|
942
|
+
WebStorage.setBatch(group.keys, group.values, scope);
|
|
943
|
+
group.keys.forEach((key, index) => cacheRawValue(scope, key, group.values[index]));
|
|
944
|
+
});
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
583
947
|
const useRawBatchPath = items.every(({
|
|
584
948
|
item
|
|
585
|
-
}) => canUseRawBatchPath(item));
|
|
949
|
+
}) => canUseRawBatchPath(asInternal(item)));
|
|
586
950
|
if (!useRawBatchPath) {
|
|
587
951
|
items.forEach(({
|
|
588
952
|
item,
|
|
@@ -592,9 +956,6 @@ function setBatch(items, scope) {
|
|
|
592
956
|
}
|
|
593
957
|
const keys = items.map(entry => entry.item.key);
|
|
594
958
|
const values = items.map(entry => entry.item.serialize(entry.value));
|
|
595
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
596
|
-
flushSecureWrites();
|
|
597
|
-
}
|
|
598
959
|
WebStorage.setBatch(keys, values, scope);
|
|
599
960
|
keys.forEach((key, index) => cacheRawValue(scope, key, values[index]));
|
|
600
961
|
}
|
|
@@ -693,4 +1054,30 @@ function runTransaction(scope, transaction) {
|
|
|
693
1054
|
throw error;
|
|
694
1055
|
}
|
|
695
1056
|
}
|
|
1057
|
+
function createSecureAuthStorage(config, options) {
|
|
1058
|
+
const ns = options?.namespace ?? "auth";
|
|
1059
|
+
const result = {};
|
|
1060
|
+
for (const key of typedKeys(config)) {
|
|
1061
|
+
const itemConfig = config[key];
|
|
1062
|
+
const expirationConfig = itemConfig.ttlMs !== undefined ? {
|
|
1063
|
+
ttlMs: itemConfig.ttlMs
|
|
1064
|
+
} : undefined;
|
|
1065
|
+
result[key] = createStorageItem({
|
|
1066
|
+
key,
|
|
1067
|
+
scope: _Storage.StorageScope.Secure,
|
|
1068
|
+
defaultValue: "",
|
|
1069
|
+
namespace: ns,
|
|
1070
|
+
...(itemConfig.biometric !== undefined ? {
|
|
1071
|
+
biometric: itemConfig.biometric
|
|
1072
|
+
} : {}),
|
|
1073
|
+
...(itemConfig.accessControl !== undefined ? {
|
|
1074
|
+
accessControl: itemConfig.accessControl
|
|
1075
|
+
} : {}),
|
|
1076
|
+
...(expirationConfig !== undefined ? {
|
|
1077
|
+
expiration: expirationConfig
|
|
1078
|
+
} : {})
|
|
1079
|
+
});
|
|
1080
|
+
}
|
|
1081
|
+
return result;
|
|
1082
|
+
}
|
|
696
1083
|
//# sourceMappingURL=index.web.js.map
|