Skip to content

Commit 72de42f

Browse files
chore: update dependencies and improve storage adapter functionality
- Bump @types/node from 25.3.0 to 25.3.3 in package.json - Downgrade react-test-renderer from 19.2.4 to 19.2.0 in package.json - Update packageManager to bun@1.3.10 in package.json - Refactor AndroidStorageAdapter to remove new architecture checks and improve context handling - Enhance AndroidStorageAdapter to handle biometric key management more effectively - Add NaN and inf checks in HybridStorage for scope and access control levels - Modify HybridStorage to use shared pointers for better memory management - Update iOSStorageAdapter to check legacy UserDefaults for un-migrated keys - Introduce new methods in storage API for string manipulation and error handling
1 parent f30fcab commit 72de42f

37 files changed

Lines changed: 1521 additions & 1183 deletions

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ Every feature in this package is documented with at least one runnable example i
4747
- Transactions — see Transactions and Atomic Balance Transfer
4848
- Migrations (`registerMigration`, `migrateToLatest`) — see Migrations
4949
- MMKV migration (`migrateFromMMKV`) — see MMKV Migration and Migrating From MMKV
50+
- Raw string API (`getString`, `setString`, `deleteString`) — see Raw String API
51+
- Keychain locked detection (`isKeychainLockedError`) — see `isKeychainLockedError(err)`
5052
- Auth storage factory (`createSecureAuthStorage`) — see Auth Token Management
5153

5254
## Requirements
@@ -280,6 +282,9 @@ import { storage, StorageScope } from "react-native-nitro-storage";
280282
| `storage.setSecureWritesAsync(enabled)` | Toggle async secure writes on Android (`false` by default) |
281283
| `storage.flushSecureWrites()` | Force flush of queued secure writes when coalescing is enabled |
282284
| `storage.setKeychainAccessGroup(group)` | Set keychain access group for app sharing (native only) |
285+
| `storage.getString(key, scope)` | Read a raw string value directly (bypasses serialization) |
286+
| `storage.setString(key, value, scope)` | Write a raw string value directly (bypasses serialization) |
287+
| `storage.deleteString(key, scope)` | Delete a raw string value by key |
283288
| `storage.import(data, scope)` | Bulk-load a `Record<string, string>` of raw key/value pairs into a scope |
284289
| `storage.setMetricsObserver(observer?)` | Subscribe to per-operation timing events |
285290
| `storage.getMetricsSnapshot()` | Get aggregate counters/latency stats keyed by operation |
@@ -509,6 +514,40 @@ const migrated = migrateFromMMKV(mmkv, myStorageItem, true);
509514

510515
---
511516

517+
### Raw String API
518+
519+
For cases where you want to bypass `createStorageItem` serialization entirely and work with raw key/value strings:
520+
521+
```ts
522+
import { storage, StorageScope } from "react-native-nitro-storage";
523+
524+
storage.setString("raw-key", "raw-value", StorageScope.Disk);
525+
const value = storage.getString("raw-key", StorageScope.Disk); // "raw-value" | undefined
526+
storage.deleteString("raw-key", StorageScope.Disk);
527+
```
528+
529+
These are synchronous and go directly to the native backend without any serialize/deserialize step.
530+
531+
---
532+
533+
### `isKeychainLockedError(err)`
534+
535+
Utility to detect iOS Keychain locked errors in secure storage operations. Returns `true` if the error was caused by a locked keychain (device locked, first unlock not yet performed, etc.). Always returns `false` on web.
536+
537+
```ts
538+
import { isKeychainLockedError } from "react-native-nitro-storage";
539+
540+
try {
541+
secureItem.get();
542+
} catch (err) {
543+
if (isKeychainLockedError(err)) {
544+
// device is locked — retry after unlock
545+
}
546+
}
547+
```
548+
549+
---
550+
512551
### Enums
513552

514553
#### `AccessControl`
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
appId: com.nitrostorage.example
2+
name: "Memory Scope"
3+
---
4+
- launchApp:
5+
clearState: true
6+
- waitForAnimationToEnd:
7+
timeout: 5000
8+
9+
# Assert initial counter value is 0
10+
- assertVisible:
11+
id: "counter-value"
12+
text: "0"
13+
14+
# Tap increment 3 times
15+
- tapOn:
16+
id: "counter-increment"
17+
- waitForAnimationToEnd
18+
19+
- tapOn:
20+
id: "counter-increment"
21+
- waitForAnimationToEnd
22+
23+
- tapOn:
24+
id: "counter-increment"
25+
- waitForAnimationToEnd
26+
27+
# Assert counter value is 3
28+
- assertVisible:
29+
id: "counter-value"
30+
text: "3"
31+
32+
# Tap decrement once
33+
- tapOn:
34+
id: "counter-decrement"
35+
- waitForAnimationToEnd
36+
37+
# Assert counter value is 2
38+
- assertVisible:
39+
id: "counter-value"
40+
text: "2"
41+
42+
# Tap reset
43+
- tapOn:
44+
id: "counter-reset"
45+
- waitForAnimationToEnd
46+
47+
# Assert counter value is 0
48+
- assertVisible:
49+
id: "counter-value"
50+
text: "0"

apps/example/.maestro/02_disk.yaml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
appId: com.nitrostorage.example
2+
name: "Disk Scope"
3+
---
4+
- launchApp:
5+
clearState: true
6+
- waitForAnimationToEnd:
7+
timeout: 5000
8+
9+
# Scroll to disk name input
10+
- scrollUntilVisible:
11+
element:
12+
id: "disk-name-input"
13+
direction: DOWN
14+
timeout: 10000
15+
centerElement: true
16+
17+
# Enter name
18+
- tapOn:
19+
id: "disk-name-input"
20+
- eraseText: 50
21+
- inputText: "alice"
22+
- waitForAnimationToEnd
23+
- hideKeyboard
24+
- waitForAnimationToEnd
25+
26+
# Scroll to save button and tap
27+
- scrollUntilVisible:
28+
element:
29+
id: "disk-save"
30+
direction: DOWN
31+
timeout: 10000
32+
centerElement: true
33+
- tapOn:
34+
id: "disk-save"
35+
- waitForAnimationToEnd
36+
37+
# Assert stored value and has value
38+
- assertVisible:
39+
id: "disk-stored-value"
40+
text: "alice"
41+
- assertVisible:
42+
id: "disk-has-value"
43+
text: "true"
44+
45+
# Delete and assert cleared
46+
- tapOn:
47+
id: "disk-delete"
48+
- waitForAnimationToEnd
49+
50+
- assertVisible:
51+
id: "disk-stored-value"
52+
text: "(empty)"
53+
- assertVisible:
54+
id: "disk-has-value"
55+
text: "false"
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
appId: com.nitrostorage.example
2+
name: "Secure Scope"
3+
---
4+
- launchApp:
5+
clearState: true
6+
- waitForAnimationToEnd:
7+
timeout: 5000
8+
9+
# Scroll to secure token input
10+
- scrollUntilVisible:
11+
element:
12+
id: "secure-token-input"
13+
direction: DOWN
14+
timeout: 10000
15+
centerElement: true
16+
17+
# Enter token
18+
- tapOn:
19+
id: "secure-token-input"
20+
- eraseText: 50
21+
- inputText: "secretabc"
22+
- waitForAnimationToEnd
23+
- hideKeyboard
24+
- waitForAnimationToEnd
25+
26+
# Scroll to lock button and tap
27+
- scrollUntilVisible:
28+
element:
29+
id: "secure-lock"
30+
direction: DOWN
31+
timeout: 10000
32+
centerElement: true
33+
- tapOn:
34+
id: "secure-lock"
35+
- waitForAnimationToEnd
36+
37+
# Assert encrypted value is visible
38+
- assertVisible:
39+
id: "secure-encrypted-value"
40+
text: "secret...."
41+
42+
# Wipe and assert not visible
43+
- tapOn:
44+
id: "secure-wipe"
45+
- waitForAnimationToEnd
46+
47+
- assertNotVisible:
48+
id: "secure-encrypted-value"
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
appId: com.nitrostorage.example
2+
name: "Namespaces"
3+
---
4+
- launchApp:
5+
clearState: true
6+
- waitForAnimationToEnd:
7+
timeout: 5000
8+
9+
# Scroll to namespace preference input
10+
- scrollUntilVisible:
11+
element:
12+
id: "ns-pref-input"
13+
direction: DOWN
14+
timeout: 10000
15+
centerElement: true
16+
17+
# Enter preference
18+
- tapOn:
19+
id: "ns-pref-input"
20+
- eraseText: 50
21+
- inputText: "dark-mode"
22+
- waitForAnimationToEnd
23+
- hideKeyboard
24+
- waitForAnimationToEnd
25+
26+
# Scroll to save button and tap
27+
- scrollUntilVisible:
28+
element:
29+
id: "ns-save"
30+
direction: DOWN
31+
timeout: 10000
32+
centerElement: true
33+
- tapOn:
34+
id: "ns-save"
35+
- waitForAnimationToEnd
36+
37+
# Assert preference value
38+
- assertVisible:
39+
id: "ns-pref-value"
40+
text: "dark-mode"
41+
42+
# Clear namespace and assert empty
43+
- tapOn:
44+
id: "ns-clear-namespace"
45+
- waitForAnimationToEnd
46+
47+
- assertVisible:
48+
id: "ns-pref-value"
49+
text: "(empty)"

apps/example/.maestro/05_json.yaml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
appId: com.nitrostorage.example
2+
name: "JSON Objects"
3+
---
4+
- launchApp:
5+
clearState: true
6+
- waitForAnimationToEnd:
7+
timeout: 5000
8+
9+
# Scroll to JSON theme toggle
10+
- scrollUntilVisible:
11+
element:
12+
id: "json-theme-toggle"
13+
direction: DOWN
14+
timeout: 10000
15+
centerElement: true
16+
17+
# Verify initial state is DARK
18+
- assertVisible:
19+
text: "DARK"
20+
21+
# Toggle theme to LIGHT
22+
- tapOn:
23+
id: "json-theme-toggle"
24+
- waitForAnimationToEnd
25+
26+
# Verify theme changed to LIGHT
27+
- assertVisible:
28+
text: "LIGHT"
29+
30+
# Toggle theme back to DARK
31+
- tapOn:
32+
id: "json-theme-toggle"
33+
- waitForAnimationToEnd
34+
35+
# Verify theme changed back to DARK
36+
- assertVisible:
37+
text: "DARK"
38+
39+
# Scroll to notification toggle
40+
- scrollUntilVisible:
41+
element:
42+
id: "json-notif-toggle"
43+
direction: DOWN
44+
timeout: 10000
45+
centerElement: true
46+
47+
# Verify initial state is ON
48+
- assertVisible:
49+
text: "ON"
50+
51+
# Toggle notifications to OFF
52+
- tapOn:
53+
id: "json-notif-toggle"
54+
- waitForAnimationToEnd
55+
56+
# Verify notifications changed to OFF
57+
- assertVisible:
58+
text: "OFF"
59+
60+
# Toggle notifications back to ON
61+
- tapOn:
62+
id: "json-notif-toggle"
63+
- waitForAnimationToEnd
64+
65+
# Verify notifications changed back to ON
66+
- assertVisible:
67+
text: "ON"
68+
69+
# Scroll to config code block
70+
- scrollUntilVisible:
71+
element:
72+
id: "json-config-code"
73+
direction: DOWN
74+
timeout: 10000
75+
centerElement: true
76+
77+
# Verify config code block is visible
78+
- assertVisible:
79+
id: "json-config-code"

apps/example/.maestro/06_auth.yaml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
appId: com.nitrostorage.example
2+
name: "Auth Storage Factory"
3+
---
4+
- launchApp:
5+
clearState: true
6+
- waitForAnimationToEnd:
7+
timeout: 5000
8+
9+
# Scroll to auth set tokens button
10+
- scrollUntilVisible:
11+
element:
12+
id: "auth-set-tokens"
13+
direction: DOWN
14+
timeout: 10000
15+
centerElement: true
16+
17+
# Verify initial state is empty
18+
- assertVisible:
19+
id: "auth-access-token-value"
20+
text: "(empty)"
21+
- assertVisible:
22+
id: "auth-refresh-token-value"
23+
text: "(empty)"
24+
25+
# Set tokens
26+
- tapOn:
27+
id: "auth-set-tokens"
28+
- waitForAnimationToEnd
29+
30+
# Verify access token is no longer empty
31+
- assertNotVisible:
32+
id: "auth-access-token-value"
33+
text: "(empty)"
34+
35+
# Clear tokens
36+
- tapOn:
37+
id: "auth-clear"
38+
- waitForAnimationToEnd
39+
40+
# Verify tokens are empty again
41+
- assertVisible:
42+
id: "auth-access-token-value"
43+
text: "(empty)"
44+
- assertVisible:
45+
id: "auth-refresh-token-value"
46+
text: "(empty)"

0 commit comments

Comments
 (0)