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.
Files changed (45) hide show
  1. package/README.md +414 -256
  2. package/android/src/main/cpp/AndroidStorageAdapterCpp.cpp +98 -11
  3. package/android/src/main/cpp/AndroidStorageAdapterCpp.hpp +15 -0
  4. package/android/src/main/java/com/nitrostorage/AndroidStorageAdapter.kt +130 -33
  5. package/android/src/main/java/com/nitrostorage/NitroStoragePackage.kt +2 -2
  6. package/cpp/bindings/HybridStorage.cpp +121 -12
  7. package/cpp/bindings/HybridStorage.hpp +10 -0
  8. package/cpp/core/NativeStorageAdapter.hpp +15 -0
  9. package/ios/IOSStorageAdapterCpp.hpp +19 -0
  10. package/ios/IOSStorageAdapterCpp.mm +233 -32
  11. package/lib/commonjs/Storage.types.js +23 -1
  12. package/lib/commonjs/Storage.types.js.map +1 -1
  13. package/lib/commonjs/index.js +173 -32
  14. package/lib/commonjs/index.js.map +1 -1
  15. package/lib/commonjs/index.web.js +289 -49
  16. package/lib/commonjs/index.web.js.map +1 -1
  17. package/lib/commonjs/internal.js +10 -0
  18. package/lib/commonjs/internal.js.map +1 -1
  19. package/lib/module/Storage.types.js +22 -0
  20. package/lib/module/Storage.types.js.map +1 -1
  21. package/lib/module/index.js +163 -35
  22. package/lib/module/index.js.map +1 -1
  23. package/lib/module/index.web.js +278 -51
  24. package/lib/module/index.web.js.map +1 -1
  25. package/lib/module/internal.js +8 -0
  26. package/lib/module/internal.js.map +1 -1
  27. package/lib/typescript/Storage.nitro.d.ts +10 -0
  28. package/lib/typescript/Storage.nitro.d.ts.map +1 -1
  29. package/lib/typescript/Storage.types.d.ts +20 -0
  30. package/lib/typescript/Storage.types.d.ts.map +1 -1
  31. package/lib/typescript/index.d.ts +30 -7
  32. package/lib/typescript/index.d.ts.map +1 -1
  33. package/lib/typescript/index.web.d.ts +40 -7
  34. package/lib/typescript/index.web.d.ts.map +1 -1
  35. package/lib/typescript/internal.d.ts +2 -0
  36. package/lib/typescript/internal.d.ts.map +1 -1
  37. package/nitrogen/generated/shared/c++/HybridStorageSpec.cpp +10 -0
  38. package/nitrogen/generated/shared/c++/HybridStorageSpec.hpp +10 -0
  39. package/package.json +4 -1
  40. package/src/Storage.nitro.ts +11 -2
  41. package/src/Storage.types.ts +22 -0
  42. package/src/index.ts +270 -71
  43. package/src/index.web.ts +431 -90
  44. package/src/internal.ts +14 -4
  45. 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.sessionStorage;
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?.setItem(key, value);
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
- return storage?.getItem(key) ?? undefined;
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?.removeItem(key);
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?.clear();
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
- storage.setItem(key, values[index]);
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 => storage?.getItem(key) ?? undefined);
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
- storage.removeItem(key);
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, config.key, listener);
520
+ unsubscribe = addKeyListener(memoryListeners, storageKey, listener);
321
521
  return;
322
522
  }
323
- unsubscribe = addKeyListener(getScopedListeners(nonMemoryScope), config.key, listener);
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(config.key);
528
+ const expiresAt = memoryExpiration.get(storageKey);
329
529
  if (expiresAt !== undefined && expiresAt <= Date.now()) {
330
- memoryExpiration.delete(config.key);
331
- memoryStore.delete(config.key);
332
- notifyKeyListeners(memoryListeners, config.key);
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(config.key);
537
+ return memoryStore.get(storageKey);
337
538
  }
338
- if (nonMemoryScope === _Storage.StorageScope.Secure && hasPendingSecureWrite(config.key)) {
339
- return readPendingSecureWrite(config.key);
539
+ if (nonMemoryScope === _Storage.StorageScope.Secure && !isBiometric && hasPendingSecureWrite(storageKey)) {
540
+ return readPendingSecureWrite(storageKey);
340
541
  }
341
542
  if (readCache) {
342
- if (hasCachedRawValue(nonMemoryScope, config.key)) {
343
- return readCachedRawValue(nonMemoryScope, config.key);
543
+ if (hasCachedRawValue(nonMemoryScope, storageKey)) {
544
+ return readCachedRawValue(nonMemoryScope, storageKey);
344
545
  }
345
546
  }
346
- const raw = WebStorage.get(config.key, config.scope);
347
- cacheRawValue(nonMemoryScope, config.key, raw);
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
- cacheRawValue(nonMemoryScope, config.key, rawValue);
555
+ if (isBiometric) {
556
+ WebStorage.setSecureBiometric(storageKey, rawValue);
557
+ return;
558
+ }
559
+ cacheRawValue(nonMemoryScope, storageKey, rawValue);
352
560
  if (coalesceSecureWrites) {
353
- scheduleSecureWrite(config.key, rawValue);
561
+ scheduleSecureWrite(storageKey, rawValue);
354
562
  return;
355
563
  }
356
564
  if (nonMemoryScope === _Storage.StorageScope.Secure) {
357
- clearPendingSecureWrite(config.key);
565
+ clearPendingSecureWrite(storageKey);
358
566
  }
359
- WebStorage.set(config.key, rawValue, config.scope);
567
+ WebStorage.set(storageKey, rawValue, config.scope);
360
568
  };
361
569
  const removeStoredRaw = () => {
362
- cacheRawValue(nonMemoryScope, config.key, undefined);
570
+ if (isBiometric) {
571
+ WebStorage.deleteSecureBiometric(storageKey);
572
+ return;
573
+ }
574
+ cacheRawValue(nonMemoryScope, storageKey, undefined);
363
575
  if (coalesceSecureWrites) {
364
- scheduleSecureWrite(config.key, undefined);
576
+ scheduleSecureWrite(storageKey, undefined);
365
577
  return;
366
578
  }
367
579
  if (nonMemoryScope === _Storage.StorageScope.Secure) {
368
- clearPendingSecureWrite(config.key);
580
+ clearPendingSecureWrite(storageKey);
369
581
  }
370
- WebStorage.remove(config.key, config.scope);
582
+ WebStorage.remove(storageKey, config.scope);
371
583
  };
372
584
  const writeValueWithoutValidation = value => {
373
585
  if (isMemory) {
374
586
  if (memoryExpiration) {
375
- memoryExpiration.set(config.key, Date.now() + (expirationTtlMs ?? 0));
587
+ memoryExpiration.set(storageKey, Date.now() + (expirationTtlMs ?? 0));
376
588
  }
377
- memoryStore.set(config.key, value);
378
- notifyKeyListeners(memoryListeners, config.key);
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 "${config.key}" in scope "${_Storage.StorageScope[config.scope]}".`);
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(config.key);
677
+ memoryExpiration.delete(storageKey);
465
678
  }
466
- memoryStore.delete(config.key);
467
- notifyKeyListeners(memoryListeners, config.key);
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: config.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