Append encrypted updates so existing compaction handles IV rotation and sync, avoiding a synchronous flush on every update.
Add regression tests. Profiled on iPhone.
Close the cached instance before acquiring the deletion flock, matching the instance-mutex-before-file-lock order used by writers. Retain the independent CRC descriptor and cross-process exclusion during deletion.
Document instance lifetime requirements and add deterministic regression coverage for writer ordering, cached and uncached removal, and cross-process exclusion. The test passes under ASan and UBSan and detects the original lock inversion.
importFrom() passes the destination no-copy views of the source's values
(KeyValueHolderCrypt::toMMBuffer() / KeyValueHolder::toMMBuffer()). An
encrypted destination keeps a value that is not stored as an offset with
KeyValueHolderCrypt(MMBuffer &&), which adopted the buffer's pointer without
checking that the buffer owns it, and freed it later on remove, overwrite or
clearAll(): a free of memory inside the source's map node or mmap, or a
double free of the source's heap buffer.
Copy a no-copy buffer instead of adopting it. Add a unit test importing plain
and encrypted stores into AES-128 and AES-256 destinations.
A first set after reopening can encode without the expiration suffix and still report success, leaving an unreadable value. Move the existing write locks and load check ahead of expiry-dependent encoding in each setter path, without adding lock acquisitions or scalar buffers. Route encoded vectors through the existing expiration helper so public templates do not need lock internals.
Keep a minimal set-succeeds/read-fails regression separate from the setter-overload coverage. Both explicitly avoid warming the lazy instance before set.
Read the expiration flag before the read-only metadata return. Filter expired entries in memory for count/allKeys instead of using fullWriteback, which refuses read-only stores. Test each API as the first operation on a fresh instance, for plain and encrypted stores, and verify filtering leaves stored entries intact.
A reopened instance starts with expiration disabled in memory. Load metadata before selecting the raw or expiration-aware read path; otherwise the first getter can return an expired value. Move the existing load check rather than adding another one.
Fix Android and iOS KMP API parity, empty-byte handling, handler behavior, and runtime version metadata. Harden standalone native interop and Maven Central publication, add smoke tests and publishing documentation, and validate the published package on a physical iPhone.
Keys longer than 65531 bytes cause keySize and computedKVSize (both uint16_t)
to wrap around, silently corrupting the internal offset so that subsequent reads
return garbage. Reject keys exceeding the safe threshold (UINT16_MAX - 4) at
all write and parse entry points.