react-native-nitro-storage 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +414 -256
- package/android/src/main/cpp/AndroidStorageAdapterCpp.cpp +98 -11
- package/android/src/main/cpp/AndroidStorageAdapterCpp.hpp +15 -0
- package/android/src/main/java/com/nitrostorage/AndroidStorageAdapter.kt +130 -33
- package/android/src/main/java/com/nitrostorage/NitroStoragePackage.kt +2 -2
- package/cpp/bindings/HybridStorage.cpp +121 -12
- package/cpp/bindings/HybridStorage.hpp +10 -0
- package/cpp/core/NativeStorageAdapter.hpp +15 -0
- package/ios/IOSStorageAdapterCpp.hpp +19 -0
- package/ios/IOSStorageAdapterCpp.mm +233 -32
- package/lib/commonjs/Storage.types.js +23 -1
- package/lib/commonjs/Storage.types.js.map +1 -1
- package/lib/commonjs/index.js +173 -32
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +289 -49
- 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/module/Storage.types.js +22 -0
- package/lib/module/Storage.types.js.map +1 -1
- package/lib/module/index.js +163 -35
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +278 -51
- 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/typescript/Storage.nitro.d.ts +10 -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 +30 -7
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/index.web.d.ts +40 -7
- 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/nitrogen/generated/shared/c++/HybridStorageSpec.cpp +10 -0
- package/nitrogen/generated/shared/c++/HybridStorageSpec.hpp +10 -0
- package/package.json +4 -1
- package/src/Storage.nitro.ts +11 -2
- package/src/Storage.types.ts +22 -0
- package/src/index.ts +270 -71
- package/src/index.web.ts +431 -90
- package/src/internal.ts +14 -4
- package/src/migration.ts +1 -1
|
@@ -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", {
|
|
@@ -30,6 +43,9 @@ var _react = require("react");
|
|
|
30
43
|
var _Storage = require("./Storage.types");
|
|
31
44
|
var _internal = require("./internal");
|
|
32
45
|
var _migration = require("./migration");
|
|
46
|
+
function asInternal(item) {
|
|
47
|
+
return item;
|
|
48
|
+
}
|
|
33
49
|
const registeredMigrations = new Map();
|
|
34
50
|
const runMicrotask = typeof queueMicrotask === "function" ? queueMicrotask : task => {
|
|
35
51
|
Promise.resolve().then(task);
|
|
@@ -40,15 +56,30 @@ const webScopeListeners = new Map([[_Storage.StorageScope.Disk, new Map()], [_St
|
|
|
40
56
|
const scopedRawCache = new Map([[_Storage.StorageScope.Disk, new Map()], [_Storage.StorageScope.Secure, new Map()]]);
|
|
41
57
|
const pendingSecureWrites = new Map();
|
|
42
58
|
let secureFlushScheduled = false;
|
|
59
|
+
const SECURE_WEB_PREFIX = "__secure_";
|
|
60
|
+
const BIOMETRIC_WEB_PREFIX = "__bio_";
|
|
61
|
+
let hasWarnedAboutWebBiometricFallback = false;
|
|
43
62
|
function getBrowserStorage(scope) {
|
|
44
63
|
if (scope === _Storage.StorageScope.Disk) {
|
|
45
64
|
return globalThis.localStorage;
|
|
46
65
|
}
|
|
47
66
|
if (scope === _Storage.StorageScope.Secure) {
|
|
48
|
-
return globalThis.
|
|
67
|
+
return globalThis.localStorage;
|
|
49
68
|
}
|
|
50
69
|
return undefined;
|
|
51
70
|
}
|
|
71
|
+
function toSecureStorageKey(key) {
|
|
72
|
+
return `${SECURE_WEB_PREFIX}${key}`;
|
|
73
|
+
}
|
|
74
|
+
function fromSecureStorageKey(key) {
|
|
75
|
+
return key.slice(SECURE_WEB_PREFIX.length);
|
|
76
|
+
}
|
|
77
|
+
function toBiometricStorageKey(key) {
|
|
78
|
+
return `${BIOMETRIC_WEB_PREFIX}${key}`;
|
|
79
|
+
}
|
|
80
|
+
function fromBiometricStorageKey(key) {
|
|
81
|
+
return key.slice(BIOMETRIC_WEB_PREFIX.length);
|
|
82
|
+
}
|
|
52
83
|
function getScopedListeners(scope) {
|
|
53
84
|
return webScopeListeners.get(scope);
|
|
54
85
|
}
|
|
@@ -147,25 +178,61 @@ const WebStorage = {
|
|
|
147
178
|
dispose: () => {},
|
|
148
179
|
set: (key, value, scope) => {
|
|
149
180
|
const storage = getBrowserStorage(scope);
|
|
150
|
-
storage
|
|
181
|
+
if (!storage) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const storageKey = scope === _Storage.StorageScope.Secure ? toSecureStorageKey(key) : key;
|
|
185
|
+
storage.setItem(storageKey, value);
|
|
151
186
|
if (scope === _Storage.StorageScope.Disk || scope === _Storage.StorageScope.Secure) {
|
|
152
187
|
notifyKeyListeners(getScopedListeners(scope), key);
|
|
153
188
|
}
|
|
154
189
|
},
|
|
155
190
|
get: (key, scope) => {
|
|
156
191
|
const storage = getBrowserStorage(scope);
|
|
157
|
-
|
|
192
|
+
const storageKey = scope === _Storage.StorageScope.Secure ? toSecureStorageKey(key) : key;
|
|
193
|
+
return storage?.getItem(storageKey) ?? undefined;
|
|
158
194
|
},
|
|
159
195
|
remove: (key, scope) => {
|
|
160
196
|
const storage = getBrowserStorage(scope);
|
|
161
|
-
storage
|
|
197
|
+
if (!storage) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (scope === _Storage.StorageScope.Secure) {
|
|
201
|
+
storage.removeItem(toSecureStorageKey(key));
|
|
202
|
+
storage.removeItem(toBiometricStorageKey(key));
|
|
203
|
+
} else {
|
|
204
|
+
storage.removeItem(key);
|
|
205
|
+
}
|
|
162
206
|
if (scope === _Storage.StorageScope.Disk || scope === _Storage.StorageScope.Secure) {
|
|
163
207
|
notifyKeyListeners(getScopedListeners(scope), key);
|
|
164
208
|
}
|
|
165
209
|
},
|
|
166
210
|
clear: scope => {
|
|
167
211
|
const storage = getBrowserStorage(scope);
|
|
168
|
-
storage
|
|
212
|
+
if (!storage) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (scope === _Storage.StorageScope.Secure) {
|
|
216
|
+
const keysToRemove = [];
|
|
217
|
+
for (let i = 0; i < storage.length; i++) {
|
|
218
|
+
const key = storage.key(i);
|
|
219
|
+
if (key?.startsWith(SECURE_WEB_PREFIX) || key?.startsWith(BIOMETRIC_WEB_PREFIX)) {
|
|
220
|
+
keysToRemove.push(key);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
keysToRemove.forEach(key => storage.removeItem(key));
|
|
224
|
+
} else if (scope === _Storage.StorageScope.Disk) {
|
|
225
|
+
const keysToRemove = [];
|
|
226
|
+
for (let i = 0; i < storage.length; i++) {
|
|
227
|
+
const key = storage.key(i);
|
|
228
|
+
if (key && !key.startsWith(SECURE_WEB_PREFIX) && !key.startsWith(BIOMETRIC_WEB_PREFIX)) {
|
|
229
|
+
keysToRemove.push(key);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
keysToRemove.forEach(key => storage.removeItem(key));
|
|
233
|
+
} else {
|
|
234
|
+
storage.clear();
|
|
235
|
+
}
|
|
169
236
|
if (scope === _Storage.StorageScope.Disk || scope === _Storage.StorageScope.Secure) {
|
|
170
237
|
notifyAllListeners(getScopedListeners(scope));
|
|
171
238
|
}
|
|
@@ -176,7 +243,8 @@ const WebStorage = {
|
|
|
176
243
|
return;
|
|
177
244
|
}
|
|
178
245
|
keys.forEach((key, index) => {
|
|
179
|
-
|
|
246
|
+
const storageKey = scope === _Storage.StorageScope.Secure ? toSecureStorageKey(key) : key;
|
|
247
|
+
storage.setItem(storageKey, values[index]);
|
|
180
248
|
});
|
|
181
249
|
if (scope === _Storage.StorageScope.Disk || scope === _Storage.StorageScope.Secure) {
|
|
182
250
|
const listeners = getScopedListeners(scope);
|
|
@@ -185,23 +253,88 @@ const WebStorage = {
|
|
|
185
253
|
},
|
|
186
254
|
getBatch: (keys, scope) => {
|
|
187
255
|
const storage = getBrowserStorage(scope);
|
|
188
|
-
return keys.map(key =>
|
|
256
|
+
return keys.map(key => {
|
|
257
|
+
const storageKey = scope === _Storage.StorageScope.Secure ? toSecureStorageKey(key) : key;
|
|
258
|
+
return storage?.getItem(storageKey) ?? undefined;
|
|
259
|
+
});
|
|
189
260
|
},
|
|
190
261
|
removeBatch: (keys, scope) => {
|
|
191
|
-
const storage = getBrowserStorage(scope);
|
|
192
|
-
if (!storage) {
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
262
|
keys.forEach(key => {
|
|
196
|
-
|
|
263
|
+
WebStorage.remove(key, scope);
|
|
197
264
|
});
|
|
198
|
-
if (scope === _Storage.StorageScope.Disk || scope === _Storage.StorageScope.Secure) {
|
|
199
|
-
const listeners = getScopedListeners(scope);
|
|
200
|
-
keys.forEach(key => notifyKeyListeners(listeners, key));
|
|
201
|
-
}
|
|
202
265
|
},
|
|
203
266
|
addOnChange: (_scope, _callback) => {
|
|
204
267
|
return () => {};
|
|
268
|
+
},
|
|
269
|
+
has: (key, scope) => {
|
|
270
|
+
const storage = getBrowserStorage(scope);
|
|
271
|
+
if (scope === _Storage.StorageScope.Secure) {
|
|
272
|
+
return storage?.getItem(toSecureStorageKey(key)) !== null || storage?.getItem(toBiometricStorageKey(key)) !== null;
|
|
273
|
+
}
|
|
274
|
+
return storage?.getItem(key) !== null;
|
|
275
|
+
},
|
|
276
|
+
getAllKeys: scope => {
|
|
277
|
+
const storage = getBrowserStorage(scope);
|
|
278
|
+
if (!storage) return [];
|
|
279
|
+
const keys = new Set();
|
|
280
|
+
for (let i = 0; i < storage.length; i++) {
|
|
281
|
+
const k = storage.key(i);
|
|
282
|
+
if (!k) {
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
if (scope === _Storage.StorageScope.Secure) {
|
|
286
|
+
if (k.startsWith(SECURE_WEB_PREFIX)) {
|
|
287
|
+
keys.add(fromSecureStorageKey(k));
|
|
288
|
+
} else if (k.startsWith(BIOMETRIC_WEB_PREFIX)) {
|
|
289
|
+
keys.add(fromBiometricStorageKey(k));
|
|
290
|
+
}
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (k.startsWith(SECURE_WEB_PREFIX) || k.startsWith(BIOMETRIC_WEB_PREFIX)) {
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
keys.add(k);
|
|
297
|
+
}
|
|
298
|
+
return Array.from(keys);
|
|
299
|
+
},
|
|
300
|
+
size: scope => {
|
|
301
|
+
return WebStorage.getAllKeys(scope).length;
|
|
302
|
+
},
|
|
303
|
+
setSecureAccessControl: () => {},
|
|
304
|
+
setKeychainAccessGroup: () => {},
|
|
305
|
+
setSecureBiometric: (key, value) => {
|
|
306
|
+
if (typeof __DEV__ !== "undefined" && __DEV__ && !hasWarnedAboutWebBiometricFallback) {
|
|
307
|
+
hasWarnedAboutWebBiometricFallback = true;
|
|
308
|
+
console.warn("[NitroStorage] Biometric storage is not supported on web. Using localStorage.");
|
|
309
|
+
}
|
|
310
|
+
globalThis.localStorage?.setItem(toBiometricStorageKey(key), value);
|
|
311
|
+
notifyKeyListeners(getScopedListeners(_Storage.StorageScope.Secure), key);
|
|
312
|
+
},
|
|
313
|
+
getSecureBiometric: key => {
|
|
314
|
+
return globalThis.localStorage?.getItem(toBiometricStorageKey(key)) ?? undefined;
|
|
315
|
+
},
|
|
316
|
+
deleteSecureBiometric: key => {
|
|
317
|
+
globalThis.localStorage?.removeItem(toBiometricStorageKey(key));
|
|
318
|
+
notifyKeyListeners(getScopedListeners(_Storage.StorageScope.Secure), key);
|
|
319
|
+
},
|
|
320
|
+
hasSecureBiometric: key => {
|
|
321
|
+
return globalThis.localStorage?.getItem(toBiometricStorageKey(key)) !== null;
|
|
322
|
+
},
|
|
323
|
+
clearSecureBiometric: () => {
|
|
324
|
+
const storage = globalThis.localStorage;
|
|
325
|
+
if (!storage) return;
|
|
326
|
+
const keysToNotify = [];
|
|
327
|
+
const toRemove = [];
|
|
328
|
+
for (let i = 0; i < storage.length; i++) {
|
|
329
|
+
const k = storage.key(i);
|
|
330
|
+
if (k?.startsWith(BIOMETRIC_WEB_PREFIX)) {
|
|
331
|
+
toRemove.push(k);
|
|
332
|
+
keysToNotify.push(fromBiometricStorageKey(k));
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
toRemove.forEach(k => storage.removeItem(k));
|
|
336
|
+
const listeners = getScopedListeners(_Storage.StorageScope.Secure);
|
|
337
|
+
keysToNotify.forEach(key => notifyKeyListeners(listeners, key));
|
|
205
338
|
}
|
|
206
339
|
};
|
|
207
340
|
function getRawValue(key, scope) {
|
|
@@ -267,15 +400,78 @@ const storage = exports.storage = {
|
|
|
267
400
|
}
|
|
268
401
|
clearScopeRawCache(scope);
|
|
269
402
|
WebStorage.clear(scope);
|
|
403
|
+
if (scope === _Storage.StorageScope.Secure) {
|
|
404
|
+
WebStorage.clearSecureBiometric();
|
|
405
|
+
}
|
|
270
406
|
},
|
|
271
407
|
clearAll: () => {
|
|
272
408
|
storage.clear(_Storage.StorageScope.Memory);
|
|
273
409
|
storage.clear(_Storage.StorageScope.Disk);
|
|
274
410
|
storage.clear(_Storage.StorageScope.Secure);
|
|
275
|
-
}
|
|
411
|
+
},
|
|
412
|
+
clearNamespace: (namespace, scope) => {
|
|
413
|
+
(0, _internal.assertValidScope)(scope);
|
|
414
|
+
if (scope === _Storage.StorageScope.Memory) {
|
|
415
|
+
for (const key of memoryStore.keys()) {
|
|
416
|
+
if ((0, _internal.isNamespaced)(key, namespace)) {
|
|
417
|
+
memoryStore.delete(key);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
notifyAllListeners(memoryListeners);
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
if (scope === _Storage.StorageScope.Secure) {
|
|
424
|
+
flushSecureWrites();
|
|
425
|
+
}
|
|
426
|
+
const keys = WebStorage.getAllKeys(scope);
|
|
427
|
+
const namespacedKeys = keys.filter(k => (0, _internal.isNamespaced)(k, namespace));
|
|
428
|
+
if (namespacedKeys.length > 0) {
|
|
429
|
+
WebStorage.removeBatch(namespacedKeys, scope);
|
|
430
|
+
namespacedKeys.forEach(k => cacheRawValue(scope, k, undefined));
|
|
431
|
+
if (scope === _Storage.StorageScope.Secure) {
|
|
432
|
+
namespacedKeys.forEach(k => clearPendingSecureWrite(k));
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
},
|
|
436
|
+
clearBiometric: () => {
|
|
437
|
+
WebStorage.clearSecureBiometric();
|
|
438
|
+
},
|
|
439
|
+
has: (key, scope) => {
|
|
440
|
+
(0, _internal.assertValidScope)(scope);
|
|
441
|
+
if (scope === _Storage.StorageScope.Memory) return memoryStore.has(key);
|
|
442
|
+
return WebStorage.has(key, scope);
|
|
443
|
+
},
|
|
444
|
+
getAllKeys: scope => {
|
|
445
|
+
(0, _internal.assertValidScope)(scope);
|
|
446
|
+
if (scope === _Storage.StorageScope.Memory) return Array.from(memoryStore.keys());
|
|
447
|
+
return WebStorage.getAllKeys(scope);
|
|
448
|
+
},
|
|
449
|
+
getAll: scope => {
|
|
450
|
+
(0, _internal.assertValidScope)(scope);
|
|
451
|
+
const result = {};
|
|
452
|
+
if (scope === _Storage.StorageScope.Memory) {
|
|
453
|
+
memoryStore.forEach((value, key) => {
|
|
454
|
+
if (typeof value === "string") result[key] = value;
|
|
455
|
+
});
|
|
456
|
+
return result;
|
|
457
|
+
}
|
|
458
|
+
const keys = WebStorage.getAllKeys(scope);
|
|
459
|
+
keys.forEach(key => {
|
|
460
|
+
const val = WebStorage.get(key, scope);
|
|
461
|
+
if (val !== undefined) result[key] = val;
|
|
462
|
+
});
|
|
463
|
+
return result;
|
|
464
|
+
},
|
|
465
|
+
size: scope => {
|
|
466
|
+
(0, _internal.assertValidScope)(scope);
|
|
467
|
+
if (scope === _Storage.StorageScope.Memory) return memoryStore.size;
|
|
468
|
+
return WebStorage.size(scope);
|
|
469
|
+
},
|
|
470
|
+
setAccessControl: _level => {},
|
|
471
|
+
setKeychainAccessGroup: _group => {}
|
|
276
472
|
};
|
|
277
473
|
function canUseRawBatchPath(item) {
|
|
278
|
-
return item._hasExpiration === false && item._hasValidation === false;
|
|
474
|
+
return item._hasExpiration === false && item._hasValidation === false && item._isBiometric !== true && item._secureAccessControl === undefined;
|
|
279
475
|
}
|
|
280
476
|
function defaultSerialize(value) {
|
|
281
477
|
return (0, _internal.serializeWithPrimitiveFastPath)(value);
|
|
@@ -284,16 +480,20 @@ function defaultDeserialize(value) {
|
|
|
284
480
|
return (0, _internal.deserializeWithPrimitiveFastPath)(value);
|
|
285
481
|
}
|
|
286
482
|
function createStorageItem(config) {
|
|
483
|
+
const storageKey = (0, _internal.prefixKey)(config.namespace, config.key);
|
|
287
484
|
const serialize = config.serialize ?? defaultSerialize;
|
|
288
485
|
const deserialize = config.deserialize ?? defaultDeserialize;
|
|
289
486
|
const isMemory = config.scope === _Storage.StorageScope.Memory;
|
|
487
|
+
const isBiometric = config.biometric === true && config.scope === _Storage.StorageScope.Secure;
|
|
488
|
+
const secureAccessControl = config.accessControl;
|
|
290
489
|
const validate = config.validate;
|
|
291
490
|
const onValidationError = config.onValidationError;
|
|
292
491
|
const expiration = config.expiration;
|
|
492
|
+
const onExpired = config.onExpired;
|
|
293
493
|
const expirationTtlMs = expiration?.ttlMs;
|
|
294
494
|
const memoryExpiration = expiration && isMemory ? new Map() : null;
|
|
295
495
|
const readCache = !isMemory && config.readCache === true;
|
|
296
|
-
const coalesceSecureWrites = config.scope === _Storage.StorageScope.Secure && config.coalesceSecureWrites === true;
|
|
496
|
+
const coalesceSecureWrites = config.scope === _Storage.StorageScope.Secure && config.coalesceSecureWrites === true && !isBiometric && secureAccessControl === undefined;
|
|
297
497
|
const nonMemoryScope = config.scope === _Storage.StorageScope.Disk ? _Storage.StorageScope.Disk : config.scope === _Storage.StorageScope.Secure ? _Storage.StorageScope.Secure : null;
|
|
298
498
|
if (expiration && expiration.ttlMs <= 0) {
|
|
299
499
|
throw new Error("expiration.ttlMs must be greater than 0.");
|
|
@@ -317,65 +517,77 @@ function createStorageItem(config) {
|
|
|
317
517
|
listeners.forEach(callback => callback());
|
|
318
518
|
};
|
|
319
519
|
if (isMemory) {
|
|
320
|
-
unsubscribe = addKeyListener(memoryListeners,
|
|
520
|
+
unsubscribe = addKeyListener(memoryListeners, storageKey, listener);
|
|
321
521
|
return;
|
|
322
522
|
}
|
|
323
|
-
unsubscribe = addKeyListener(getScopedListeners(nonMemoryScope),
|
|
523
|
+
unsubscribe = addKeyListener(getScopedListeners(nonMemoryScope), storageKey, listener);
|
|
324
524
|
};
|
|
325
525
|
const readStoredRaw = () => {
|
|
326
526
|
if (isMemory) {
|
|
327
527
|
if (memoryExpiration) {
|
|
328
|
-
const expiresAt = memoryExpiration.get(
|
|
528
|
+
const expiresAt = memoryExpiration.get(storageKey);
|
|
329
529
|
if (expiresAt !== undefined && expiresAt <= Date.now()) {
|
|
330
|
-
memoryExpiration.delete(
|
|
331
|
-
memoryStore.delete(
|
|
332
|
-
notifyKeyListeners(memoryListeners,
|
|
530
|
+
memoryExpiration.delete(storageKey);
|
|
531
|
+
memoryStore.delete(storageKey);
|
|
532
|
+
notifyKeyListeners(memoryListeners, storageKey);
|
|
533
|
+
onExpired?.(storageKey);
|
|
333
534
|
return undefined;
|
|
334
535
|
}
|
|
335
536
|
}
|
|
336
|
-
return memoryStore.get(
|
|
537
|
+
return memoryStore.get(storageKey);
|
|
337
538
|
}
|
|
338
|
-
if (nonMemoryScope === _Storage.StorageScope.Secure && hasPendingSecureWrite(
|
|
339
|
-
return readPendingSecureWrite(
|
|
539
|
+
if (nonMemoryScope === _Storage.StorageScope.Secure && !isBiometric && hasPendingSecureWrite(storageKey)) {
|
|
540
|
+
return readPendingSecureWrite(storageKey);
|
|
340
541
|
}
|
|
341
542
|
if (readCache) {
|
|
342
|
-
if (hasCachedRawValue(nonMemoryScope,
|
|
343
|
-
return readCachedRawValue(nonMemoryScope,
|
|
543
|
+
if (hasCachedRawValue(nonMemoryScope, storageKey)) {
|
|
544
|
+
return readCachedRawValue(nonMemoryScope, storageKey);
|
|
344
545
|
}
|
|
345
546
|
}
|
|
346
|
-
|
|
347
|
-
|
|
547
|
+
if (isBiometric) {
|
|
548
|
+
return WebStorage.getSecureBiometric(storageKey);
|
|
549
|
+
}
|
|
550
|
+
const raw = WebStorage.get(storageKey, config.scope);
|
|
551
|
+
cacheRawValue(nonMemoryScope, storageKey, raw);
|
|
348
552
|
return raw;
|
|
349
553
|
};
|
|
350
554
|
const writeStoredRaw = rawValue => {
|
|
351
|
-
|
|
555
|
+
if (isBiometric) {
|
|
556
|
+
WebStorage.setSecureBiometric(storageKey, rawValue);
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
cacheRawValue(nonMemoryScope, storageKey, rawValue);
|
|
352
560
|
if (coalesceSecureWrites) {
|
|
353
|
-
scheduleSecureWrite(
|
|
561
|
+
scheduleSecureWrite(storageKey, rawValue);
|
|
354
562
|
return;
|
|
355
563
|
}
|
|
356
564
|
if (nonMemoryScope === _Storage.StorageScope.Secure) {
|
|
357
|
-
clearPendingSecureWrite(
|
|
565
|
+
clearPendingSecureWrite(storageKey);
|
|
358
566
|
}
|
|
359
|
-
WebStorage.set(
|
|
567
|
+
WebStorage.set(storageKey, rawValue, config.scope);
|
|
360
568
|
};
|
|
361
569
|
const removeStoredRaw = () => {
|
|
362
|
-
|
|
570
|
+
if (isBiometric) {
|
|
571
|
+
WebStorage.deleteSecureBiometric(storageKey);
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
cacheRawValue(nonMemoryScope, storageKey, undefined);
|
|
363
575
|
if (coalesceSecureWrites) {
|
|
364
|
-
scheduleSecureWrite(
|
|
576
|
+
scheduleSecureWrite(storageKey, undefined);
|
|
365
577
|
return;
|
|
366
578
|
}
|
|
367
579
|
if (nonMemoryScope === _Storage.StorageScope.Secure) {
|
|
368
|
-
clearPendingSecureWrite(
|
|
580
|
+
clearPendingSecureWrite(storageKey);
|
|
369
581
|
}
|
|
370
|
-
WebStorage.remove(
|
|
582
|
+
WebStorage.remove(storageKey, config.scope);
|
|
371
583
|
};
|
|
372
584
|
const writeValueWithoutValidation = value => {
|
|
373
585
|
if (isMemory) {
|
|
374
586
|
if (memoryExpiration) {
|
|
375
|
-
memoryExpiration.set(
|
|
587
|
+
memoryExpiration.set(storageKey, Date.now() + (expirationTtlMs ?? 0));
|
|
376
588
|
}
|
|
377
|
-
memoryStore.set(
|
|
378
|
-
notifyKeyListeners(memoryListeners,
|
|
589
|
+
memoryStore.set(storageKey, value);
|
|
590
|
+
notifyKeyListeners(memoryListeners, storageKey);
|
|
379
591
|
return;
|
|
380
592
|
}
|
|
381
593
|
const serialized = serialize(value);
|
|
@@ -434,6 +646,7 @@ function createStorageItem(config) {
|
|
|
434
646
|
if (parsed.expiresAt <= Date.now()) {
|
|
435
647
|
removeStoredRaw();
|
|
436
648
|
invalidateParsedCache();
|
|
649
|
+
onExpired?.(storageKey);
|
|
437
650
|
lastValue = ensureValidatedValue(config.defaultValue, false);
|
|
438
651
|
hasLastValue = true;
|
|
439
652
|
return lastValue;
|
|
@@ -453,7 +666,7 @@ function createStorageItem(config) {
|
|
|
453
666
|
const newValue = typeof valueOrFn === "function" ? valueOrFn(currentValue) : valueOrFn;
|
|
454
667
|
invalidateParsedCache();
|
|
455
668
|
if (validate && !validate(newValue)) {
|
|
456
|
-
throw new Error(`Validation failed for key "${
|
|
669
|
+
throw new Error(`Validation failed for key "${storageKey}" in scope "${_Storage.StorageScope[config.scope]}".`);
|
|
457
670
|
}
|
|
458
671
|
writeValueWithoutValidation(newValue);
|
|
459
672
|
};
|
|
@@ -461,14 +674,19 @@ function createStorageItem(config) {
|
|
|
461
674
|
invalidateParsedCache();
|
|
462
675
|
if (isMemory) {
|
|
463
676
|
if (memoryExpiration) {
|
|
464
|
-
memoryExpiration.delete(
|
|
677
|
+
memoryExpiration.delete(storageKey);
|
|
465
678
|
}
|
|
466
|
-
memoryStore.delete(
|
|
467
|
-
notifyKeyListeners(memoryListeners,
|
|
679
|
+
memoryStore.delete(storageKey);
|
|
680
|
+
notifyKeyListeners(memoryListeners, storageKey);
|
|
468
681
|
return;
|
|
469
682
|
}
|
|
470
683
|
removeStoredRaw();
|
|
471
684
|
};
|
|
685
|
+
const hasItem = () => {
|
|
686
|
+
if (isMemory) return memoryStore.has(storageKey);
|
|
687
|
+
if (isBiometric) return WebStorage.hasSecureBiometric(storageKey);
|
|
688
|
+
return WebStorage.has(storageKey, config.scope);
|
|
689
|
+
};
|
|
472
690
|
const subscribe = callback => {
|
|
473
691
|
ensureSubscription();
|
|
474
692
|
listeners.add(callback);
|
|
@@ -484,6 +702,7 @@ function createStorageItem(config) {
|
|
|
484
702
|
get,
|
|
485
703
|
set,
|
|
486
704
|
delete: deleteItem,
|
|
705
|
+
has: hasItem,
|
|
487
706
|
subscribe,
|
|
488
707
|
serialize,
|
|
489
708
|
deserialize,
|
|
@@ -494,8 +713,10 @@ function createStorageItem(config) {
|
|
|
494
713
|
_hasValidation: validate !== undefined,
|
|
495
714
|
_hasExpiration: expiration !== undefined,
|
|
496
715
|
_readCacheEnabled: readCache,
|
|
716
|
+
_isBiometric: isBiometric,
|
|
717
|
+
_secureAccessControl: secureAccessControl,
|
|
497
718
|
scope: config.scope,
|
|
498
|
-
key:
|
|
719
|
+
key: storageKey
|
|
499
720
|
};
|
|
500
721
|
return storageItem;
|
|
501
722
|
}
|
|
@@ -582,7 +803,7 @@ function setBatch(items, scope) {
|
|
|
582
803
|
}
|
|
583
804
|
const useRawBatchPath = items.every(({
|
|
584
805
|
item
|
|
585
|
-
}) => canUseRawBatchPath(item));
|
|
806
|
+
}) => canUseRawBatchPath(asInternal(item)));
|
|
586
807
|
if (!useRawBatchPath) {
|
|
587
808
|
items.forEach(({
|
|
588
809
|
item,
|
|
@@ -693,4 +914,23 @@ function runTransaction(scope, transaction) {
|
|
|
693
914
|
throw error;
|
|
694
915
|
}
|
|
695
916
|
}
|
|
917
|
+
function createSecureAuthStorage(config, options) {
|
|
918
|
+
const ns = options?.namespace ?? "auth";
|
|
919
|
+
const result = {};
|
|
920
|
+
for (const key of Object.keys(config)) {
|
|
921
|
+
const itemConfig = config[key];
|
|
922
|
+
result[key] = createStorageItem({
|
|
923
|
+
key,
|
|
924
|
+
scope: _Storage.StorageScope.Secure,
|
|
925
|
+
defaultValue: "",
|
|
926
|
+
namespace: ns,
|
|
927
|
+
biometric: itemConfig.biometric,
|
|
928
|
+
accessControl: itemConfig.accessControl,
|
|
929
|
+
expiration: itemConfig.ttlMs ? {
|
|
930
|
+
ttlMs: itemConfig.ttlMs
|
|
931
|
+
} : undefined
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
return result;
|
|
935
|
+
}
|
|
696
936
|
//# sourceMappingURL=index.web.js.map
|