Releases: rust-dd/react-native-scc
Release list
v0.2.0
What's new in 0.2.0
Atomic transactions
kv.transaction(async (tx) => { ... }) now commits as a single crash-atomic native batch: all staged operations go through one applyBatch native call backed by a new Op::Batch WAL record — either the whole transaction is durable or none of it is. This replaces the optimistic-concurrency retry loop, which could not detect real concurrency in single-threaded JS and threw spurious conflict failures.
Transaction staging is also safer:
- Staged
ArrayBuffers are copied at staging time, andtx.getJSONreturns a parsed snapshot — mutating your object or buffer between staging and commit can no longer desync what gets written. - A transaction body that throws or rejects discards all staged writes.
In-memory eviction
maxEntries and ttlSweepIntervalMs now apply to in-memory stores too (previously disk-only). A background sweeper thread expires TTL'd keys and evicts over-limit entries, sharing the eviction-selection logic with the disk writer. The sweeper is stopped and joined on close(), and expired keys are removed under an entry-lock re-check so a concurrent rewrite is never clobbered.
New hook: useKVSelector
Subscribe to a derived slice of a JSON value with an optional custom equality function. Selector and equality functions are kept in refs, so inline selectors don't resubscribe on every render, and object-returning selectors can't cause an update loop.
Durability and correctness fixes
- Batch WAL appends are guarded against concurrent compaction with a per-store RwLock: a snapshot can never capture a half-applied batch and then truncate its record away.
- The sweeper counts live entries exactly, so it no longer over-evicts live keys when more than 4096 keys expire in a single sweep; the WAL sweep deadline uses
checked_addto avoid anInstantoverflow panic. - Oversized values now fail fast with a
RecordTooLargeerror instead of writing a broken WAL record. - Reopening an already-open store with different
OpenOptions(or withrecreate: true) returns a configuration error instead of silently reusing the first store — for both disk and in-memory stores. encodeBatchfalls back to a manual UTF-8 encoder whereTextEncoderis unavailable (JSC, older Hermes); batchdeletenotifies listeners only when the key actually existed.
Example app
New demo cards for an atomic-transfer transaction, namespaced counters, and useKVSelector (with a visible render count), plus self-test coverage for transaction commit, namespace scoping and clearAll, observeJSON, and in-memory maxEntries eviction.
Full Changelog: v0.1.1...v0.2.0
v0.1.1
v0.1.0
Initial release: ultra-low-latency, persistent key-value storage for React Native and Expo — a Rust core on scc (lock-free concurrent hash map) behind Nitro Modules.
Highlights
- All reads served from RAM; writes stream to a crash-safe write-ahead log on a background thread (group commits, CRC-protected recovery, atomic snapshot compaction)
- Sync + async APIs, batch setMany/getMany crossing the bridge once
- Encryption at rest (ChaCha20-Poly1305, per instance)
- Per-key TTL with a background sweeper, optional maxEntries eviction cap
- Native change events: listeners and hooks react to writes from any handle of the same store
- React hooks (useKVString/Number/Boolean/Buffer/JSON) and zustand / jotai / redux-persist adapters as subpath exports
- Zero-config persistence (iOS Application Support, Android filesDir), multiple independent stores
- Prebuilt binaries for iOS (arm64 + simulator) and Android (arm64-v8a, armeabi-v7a, x86_64, x86) — no Rust toolchain needed
Install
npm install react-native-scc-storage react-native-nitro-modulesExpo:
{
"expo": { "plugins": ["react-native-scc-storage"]}
}