@@ -14,6 +14,10 @@ Synchronous Memory, Disk, and Secure storage in one unified API — powered by [
1414- ** Biometric storage** — hardware-backed biometric protection on iOS & Android
1515- ** Auth storage factory** — ` createSecureAuthStorage ` for multi-token auth flows
1616- ** Batch operations** — atomic multi-key get/set/remove via native batch APIs
17+ - ** Prefix queries** — fast key/value scans with ` storage.getKeysByPrefix ` and ` storage.getByPrefix `
18+ - ** Versioned writes** — optimistic concurrency with ` item.getWithVersion() ` and ` item.setIfVersion(...) `
19+ - ** Performance metrics** — observe operation timings and aggregate snapshots
20+ - ** Web secure backend override** — plug custom secure storage backend on web
1721- ** Transactions** — grouped writes with automatic rollback on error
1822- ** Migrations** — versioned data migrations with ` registerMigration ` / ` migrateToLatest `
1923- ** MMKV migration** — drop-in ` migrateFromMMKV ` for painless migration from MMKV
@@ -31,6 +35,10 @@ Every feature in this package is documented with at least one runnable example i
3135- Validation + recovery — see Feature Flags with Validation
3236- Biometric + access control — see Biometric-protected Secrets
3337- Global storage utilities (` clear* ` , ` has ` , ` getAll* ` , ` size ` , secure write settings) — see Global utility examples and Storage Snapshots and Cleanup
38+ - Prefix utilities (` getKeysByPrefix ` , ` getByPrefix ` ) — see Prefix Queries and Namespace Inspection
39+ - Versioned item API (` getWithVersion ` , ` setIfVersion ` ) — see Optimistic Versioned Writes
40+ - Metrics API (` setMetricsObserver ` , ` getMetricsSnapshot ` , ` resetMetrics ` ) — see Storage Metrics Instrumentation
41+ - Web secure backend override (` setWebSecureStorageBackend ` , ` getWebSecureStorageBackend ` ) — see Custom Web Secure Backend
3442- Batch APIs (` getBatch ` , ` setBatch ` , ` removeBatch ` ) — see Batch Operations and Bulk Bootstrap with Batch APIs
3543- Transactions — see Transactions and Atomic Balance Transfer
3644- Migrations (` registerMigration ` , ` migrateToLatest ` ) — see Migrations
@@ -185,21 +193,24 @@ function createStorageItem<T = undefined>(
185193| ` coalesceSecureWrites ` | ` boolean ` | ` false ` | Batch same-tick Secure writes per key |
186194| ` namespace ` | ` string ` | — | Prefix key as ` namespace:key ` for isolation |
187195| ` biometric ` | ` boolean ` | ` false ` | Require biometric auth (Secure scope only) |
196+ | ` biometricLevel ` | ` BiometricLevel ` | ` None ` | Biometric policy (` BiometryOrPasscode ` / ` BiometryOnly ` ) |
188197| ` accessControl ` | ` AccessControl ` | — | Keychain access control level (native only) |
189198
190199** Returned ` StorageItem<T> ` :**
191200
192- | Method / Property | Type | Description |
193- | ----------------- | ---------------------------------------- | -------------------------------------------------- |
194- | ` get() ` | ` () => T ` | Read current value (synchronous) |
195- | ` set(value) ` | ` (value: T \| ((prev: T) => T)) => void ` | Write a value or updater function |
196- | ` delete() ` | ` () => void ` | Remove the stored value (resets to ` defaultValue ` ) |
197- | ` has() ` | ` () => boolean ` | Check if a value exists in storage |
198- | ` subscribe(cb) ` | ` (cb: () => void) => () => void ` | Listen for changes, returns unsubscribe |
199- | ` serialize ` | ` (v: T) => string ` | The item's serializer |
200- | ` deserialize ` | ` (v: string) => T ` | The item's deserializer |
201- | ` scope ` | ` StorageScope ` | The item's scope |
202- | ` key ` | ` string ` | The resolved key (includes namespace prefix) |
201+ | Method / Property | Type | Description |
202+ | ------------------- | -------------------------------------------------------------------- | ------------------------------------------------------ |
203+ | ` get() ` | ` () => T ` | Read current value (synchronous) |
204+ | ` getWithVersion() ` | ` () => { value: T; version: StorageVersion } ` | Read value plus current storage version token |
205+ | ` set(value) ` | ` (value: T \| ((prev: T) => T)) => void ` | Write a value or updater function |
206+ | ` setIfVersion(...) ` | ` (version: StorageVersion, value: T \| ((prev: T) => T)) => boolean ` | Write only if version matches (optimistic concurrency) |
207+ | ` delete() ` | ` () => void ` | Remove the stored value (resets to ` defaultValue ` ) |
208+ | ` has() ` | ` () => boolean ` | Check if a value exists in storage |
209+ | ` subscribe(cb) ` | ` (cb: () => void) => () => void ` | Listen for changes, returns unsubscribe |
210+ | ` serialize ` | ` (v: T) => string ` | The item's serializer |
211+ | ` deserialize ` | ` (v: string) => T ` | The item's deserializer |
212+ | ` scope ` | ` StorageScope ` | The item's scope |
213+ | ` key ` | ` string ` | The resolved key (includes namespace prefix) |
203214
204215** Non-React subscription example:**
205216
@@ -249,30 +260,41 @@ setToken("new-token");
249260import { storage , StorageScope } from " react-native-nitro-storage" ;
250261```
251262
252- | Method | Description |
253- | --------------------------------------- | ---------------------------------------------------------------------------- |
254- | ` storage.clear(scope) ` | Clear all keys in a scope (` Secure ` also clears biometric entries) |
255- | ` storage.clearAll() ` | Clear Memory + Disk + Secure |
256- | ` storage.clearNamespace(ns, scope) ` | Remove only keys matching a namespace |
257- | ` storage.clearBiometric() ` | Remove all biometric-prefixed keys |
258- | ` storage.has(key, scope) ` | Check if a key exists |
259- | ` storage.getAllKeys(scope) ` | Get all key names |
260- | ` storage.getAll(scope) ` | Get all key-value pairs as ` Record<string, string> ` |
261- | ` storage.size(scope) ` | Number of stored keys |
262- | ` storage.setAccessControl(level) ` | Set default secure access control for subsequent secure writes (native only) |
263- | ` storage.setSecureWritesAsync(enabled) ` | Toggle async secure writes on Android (` false ` by default) |
264- | ` storage.flushSecureWrites() ` | Force flush of queued secure writes when coalescing is enabled |
265- | ` storage.setKeychainAccessGroup(group) ` | Set keychain access group for app sharing (native only) |
263+ | Method | Description |
264+ | ---------------------------------------- | ---------------------------------------------------------------------------- |
265+ | ` storage.clear(scope) ` | Clear all keys in a scope (` Secure ` also clears biometric entries) |
266+ | ` storage.clearAll() ` | Clear Memory + Disk + Secure |
267+ | ` storage.clearNamespace(ns, scope) ` | Remove only keys matching a namespace |
268+ | ` storage.clearBiometric() ` | Remove all biometric-prefixed keys |
269+ | ` storage.has(key, scope) ` | Check if a key exists |
270+ | ` storage.getAllKeys(scope) ` | Get all key names |
271+ | ` storage.getKeysByPrefix(prefix, scope) ` | Get keys that start with a prefix |
272+ | ` storage.getByPrefix(prefix, scope) ` | Get raw key-value pairs for keys matching a prefix |
273+ | ` storage.getAll(scope) ` | Get all key-value pairs as ` Record<string, string> ` |
274+ | ` storage.size(scope) ` | Number of stored keys |
275+ | ` storage.setAccessControl(level) ` | Set default secure access control for subsequent secure writes (native only) |
276+ | ` storage.setSecureWritesAsync(enabled) ` | Toggle async secure writes on Android (` false ` by default) |
277+ | ` storage.flushSecureWrites() ` | Force flush of queued secure writes when coalescing is enabled |
278+ | ` storage.setKeychainAccessGroup(group) ` | Set keychain access group for app sharing (native only) |
279+ | ` storage.setMetricsObserver(observer?) ` | Subscribe to per-operation timing events |
280+ | ` storage.getMetricsSnapshot() ` | Get aggregate counters/latency stats keyed by operation |
281+ | ` storage.resetMetrics() ` | Reset in-memory metrics counters |
266282
267283> ` storage.getAll(StorageScope.Secure) ` returns regular secure entries. Biometric-protected values are not included in this snapshot API.
268284
269285#### Global utility examples
270286
271287``` ts
272- import { AccessControl , storage , StorageScope } from " react-native-nitro-storage" ;
288+ import {
289+ AccessControl ,
290+ storage ,
291+ StorageScope ,
292+ } from " react-native-nitro-storage" ;
273293
274294storage .has (" session" , StorageScope .Disk );
275295storage .getAllKeys (StorageScope .Disk );
296+ storage .getKeysByPrefix (" user-42:" , StorageScope .Disk );
297+ storage .getByPrefix (" user-42:" , StorageScope .Disk );
276298storage .getAll (StorageScope .Disk );
277299storage .size (StorageScope .Disk );
278300
@@ -303,6 +325,28 @@ storage.setSecureWritesAsync(true);
303325storage .flushSecureWrites (); // deterministic durability boundary
304326```
305327
328+ #### Custom web secure backend
329+
330+ By default, web Secure scope uses ` localStorage ` with ` __secure_ ` key prefixing. You can replace it with a custom backend (for example encrypted IndexedDB adapter).
331+
332+ ``` ts
333+ import {
334+ getWebSecureStorageBackend ,
335+ setWebSecureStorageBackend ,
336+ } from " react-native-nitro-storage" ;
337+
338+ setWebSecureStorageBackend ({
339+ getItem : (key ) => encryptedStore .get (key ) ?? null ,
340+ setItem : (key , value ) => encryptedStore .set (key , value ),
341+ removeItem : (key ) => encryptedStore .delete (key ),
342+ clear : () => encryptedStore .clear (),
343+ getAllKeys : () => encryptedStore .keys (),
344+ });
345+
346+ const backend = getWebSecureStorageBackend ();
347+ console .log (" custom backend active:" , backend !== undefined );
348+ ```
349+
306350---
307351
308352### ` createSecureAuthStorage<K>(config, options?) `
@@ -318,7 +362,7 @@ function createSecureAuthStorage<K extends string>(
318362
319363- Default namespace: ` "auth" `
320364- Each key is a separate ` StorageItem<string> ` with ` StorageScope.Secure `
321- - Supports per-key TTL, biometric, and access control
365+ - Supports per-key TTL, biometric level policy , and access control
322366
323367---
324368
@@ -550,13 +594,18 @@ const flagsItem = createStorageItem<FeatureFlags>({
550594### Biometric-protected Secrets
551595
552596``` ts
553- import { AccessControl , createStorageItem , StorageScope } from " react-native-nitro-storage" ;
597+ import {
598+ AccessControl ,
599+ BiometricLevel ,
600+ createStorageItem ,
601+ StorageScope ,
602+ } from " react-native-nitro-storage" ;
554603
555604const paymentPin = createStorageItem <string >({
556605 key: " payment-pin" ,
557606 scope: StorageScope .Secure ,
558607 defaultValue: " " ,
559- biometric: true ,
608+ biometricLevel: BiometricLevel . BiometryOnly ,
560609 accessControl: AccessControl .WhenPasscodeSetThisDeviceOnly ,
561610});
562611
@@ -686,7 +735,11 @@ const compactItem = createStorageItem<{ id: number; active: boolean }>({
686735### Coalesced Secure Writes with Deterministic Flush
687736
688737``` ts
689- import { createStorageItem , storage , StorageScope } from " react-native-nitro-storage" ;
738+ import {
739+ createStorageItem ,
740+ storage ,
741+ StorageScope ,
742+ } from " react-native-nitro-storage" ;
690743
691744const sessionToken = createStorageItem <string >({
692745 key: " session-token" ,
@@ -718,6 +771,58 @@ if (storage.has("legacy-flag", StorageScope.Disk)) {
718771storage .clearBiometric ();
719772```
720773
774+ ### Prefix Queries and Namespace Inspection
775+
776+ ``` ts
777+ import { storage , StorageScope } from " react-native-nitro-storage" ;
778+
779+ const userKeys = storage .getKeysByPrefix (" user-42:" , StorageScope .Disk );
780+ const userRawEntries = storage .getByPrefix (" user-42:" , StorageScope .Disk );
781+
782+ console .log (userKeys );
783+ console .log (userRawEntries );
784+ ```
785+
786+ ### Optimistic Versioned Writes
787+
788+ ``` ts
789+ import { createStorageItem , StorageScope } from " react-native-nitro-storage" ;
790+
791+ const profileItem = createStorageItem ({
792+ key: " profile" ,
793+ scope: StorageScope .Disk ,
794+ defaultValue: { name: " Guest" },
795+ });
796+
797+ const snapshot = profileItem .getWithVersion ();
798+ const didWrite = profileItem .setIfVersion (snapshot .version , {
799+ ... snapshot .value ,
800+ name: " Ada" ,
801+ });
802+
803+ if (! didWrite ) {
804+ // value changed since snapshot; reload and retry
805+ }
806+ ```
807+
808+ ### Storage Metrics Instrumentation
809+
810+ ``` ts
811+ import { storage } from " react-native-nitro-storage" ;
812+
813+ storage .setMetricsObserver ((event ) => {
814+ console .log (
815+ ` [nitro-storage] ${event .operation } scope=${event .scope } duration=${event .durationMs }ms keys=${event .keysCount } ` ,
816+ );
817+ });
818+
819+ const metrics = storage .getMetricsSnapshot ();
820+ console .log (metrics [" item:get" ]?.avgDurationMs );
821+
822+ storage .resetMetrics ();
823+ storage .setMetricsObserver (undefined );
824+ ```
825+
721826### Low-level Subscription (outside React)
722827
723828``` ts
@@ -769,6 +874,12 @@ import type {
769874 MigrationContext ,
770875 Migration ,
771876 TransactionContext ,
877+ StorageVersion ,
878+ VersionedValue ,
879+ StorageMetricsEvent ,
880+ StorageMetricsObserver ,
881+ StorageMetricSummary ,
882+ WebSecureStorageBackend ,
772883 MMKVLike ,
773884 SecureAuthStorageConfig ,
774885} from " react-native-nitro-storage" ;
0 commit comments