keep 1.0.0
keep: ^1.0.0 copied to clipboard
Typed, reactive, encrypted local storage for Flutter.
1.0.0 #
This is a major release focused on data durability, reactivity correctness, and concurrency safety. Several long-standing bugs that could cause silent data loss or stale UI have been fixed. Most changes are transparent to existing code, but a few have behavioral implications — see Migration Notes at the end.
Durability (BREAKING) #
- Bug Fix:
await keepKey.write(value)for internal storage now blocks until the value is durably persisted to disk. PreviouslysaveMemory()was fire-and-forget (unawaited), so a process crash immediately afterawait write()could lose the written value despite the apparent success. - Bug Fix:
Keep.dispose()now flushes all pending writes to disk before tearing down the writer queues. Previously pending debounced writes were cancelled and their data lost forever. - Bug Fix: When a debounced pending operation is superseded by a newer one
(
KeepWriteQueue.run), the original caller's future is now resolved with the successor's outcome instead of being silently completed withnull. This guarantees thatawait write(...)returning means data is persistent for every caller in a debounce chain, not just the most recent one. - New API:
Keep.flush()drains all pending writes to disk across both internal and external storage. Useful after fire-and-forgetunawaited(write(...))patterns or before snapshotting the storage directory. - New API:
KeepStorage.flush()interface method (default no-op) lets storage adapters expose their flush semantics. - New API:
KeepWriteQueue.flush()waits for all in-flight and pending operations to settle without cancelling them;awaitSettled(id)waits for a specific id.
Reactivity (BREAKING) #
- Bug Fix:
KeepKey.remove()now invalidates the in-memory value cache and emits a change event ononChangeController. Previously a removed key kept returning its stale cached value fromreadSync()/read(), and listeners (KeepBuilder,key.stream) never observed the removal. - Bug Fix:
Keep.clear()andKeep.clearRemovable()now invalidate the per-key caches of all (or removable) registered keys before notifying listeners. - Bug Fix:
KeepBuilderis now aStatefulWidgetthat holds the latest value in widget state. Previously theStreamBuilder+FutureBuildercombination issued a freshread()future on every parent rebuild, causing flicker and transientnullframes.
Storage Engine #
- Bug Fix: Concurrent external reads on the same key no longer return
phantom
nulldue to the writer queue's debounce. Reads now bypass the queue and useawaitSettledto observe in-flight writes without participating in cancellation. - Bug Fix: External storage
read()/readSync()no longer delete the underlying file when decoding returnsnull, completing the 0.7.0 fix that already removed this automatic deletion in error paths. - Bug Fix:
KeepInternalStorage.read()now awaitsKeep.ensureInitializedso callers that bypass theKeepKeywrapper still observe a fully loaded memory map.
Robustness #
- Bug Fix:
Keep.init()now wraps initialization in atry/catchand completes its internal completer with an error on failure. Previously a failed init left the completer permanently pending, causing every subsequentensureInitializedawait to hang forever. - Bug Fix:
KeepKey.update()now serializes concurrent atomic updates targeting the same key via a per-key mutex (Keep.runSerialized), preventing classic lost-update races where two callers read the same value and overwrite each other. - Bug Fix:
SubKeyManager.toList()no longer silently swallows header read errors; failures are now surfaced viaKeep.onError. - Bug Fix: All
onChangeController.add(...)call sites guard against a closed controller, preventing crashes when a fire-and-forget write resolves afterKeep.dispose().
Security #
- Improvement:
SimpleKeepEncrypternow asserts thatsecureKeyis at least 8 characters long. - Improvement:
Keep.init()emits a debug-mode warning when the default fallbackSimpleKeepEncrypteris used together with anyKeepKeySecure, since the default key is a public constant that offers only basic obfuscation.
Codec #
- Bug Fix:
shiftBytesandunShiftBytesno longer mutate their input buffer; they return a freshly allocatedUint8List. The defensiveUint8List.fromListcopy insideKeepCodecOfhas been removed since the mixin is now safe.
Migration Notes #
await keepKey.write(value)for internal storage is now stricter about durability and therefore slower for sequential awaited writes (roughly matching external storage throughput). For high-frequency writes that previously relied on fire-and-forget semantics, switch tounawaited(write(...))followed by a singleawait keep.flush()at the appropriate flush point — supersede chaining still coalesces these into a single disk write while preserving durability for every awaiter.- Custom
KeepStorageimplementations may overrideflush()to expose their own queue draining; the default implementation is a no-op. - Code that depended on
shiftBytes/unShiftBytesmutating in place must now use the returnedUint8List.
0.7.0 #
- Performance: Implemented
nullvalue caching inKeepKeyPlainandKeepKeySecureto prevent unnecessary repeated disk I/O when reading non-existent keys. - Performance: Updated
writemethods to immediately cache the newly written value, avoiding an extra disk read on the subsequentreadcall. - Bug Fix: Removed
unawaited(remove())from the catch blocks inreadandreadSyncmethods for bothKeepKeyPlainandKeepKeySecure. This prevents disastrous automatic deletion of user data when a simple parsing or schema error occurs.
0.6.0 #
- Binary Codec (V2): Switched from JSON-based encoding to
StandardMessageCodecfor significant performance gains and smaller storage footprint. - Improved Performance: Optimized binary serialization for complex and nested data structures.
- Auto-Migration: Automatic seamless migration from V1 (JSON) to V2 (Binary) format on first write.
- Better Field Support: Updated codec interface to use
Object?for improved type precision. - Stability: Enhanced internal batch encoding logic for better memory efficiency.
0.5.3 #
- Fixed race condition in atomic writes.
- Fixed race condition in initialization.
0.5.2 #
- Refactored file write operations with a robust
atomicWriteutility. - Added explicit directory checks and temporary file validation to prevent
PathNotFoundExceptionduring atomic swaps. - Improved error handling by ensuring temporary files are cleaned up on failure.
- Specialized for better stability on emulators and slow file systems.
0.5.1 #
Added #
- Uint8List Support: New
kBytesandkBytesSecurefactories for efficient byte array storage. - Custom Serialization for Secure Keys: Secure factories now support optional
fromStorageandtoStoragemappers.
Changed #
- Performance: General optimizations for better memory efficiency and speed.
- Code Clarity: Improved internal factory logic for better readability.
0.5.0 #
Added #
- Multi-Instance Support: Multiple
Keepinstances can now run concurrently with independent registries and storage locations.Keepconstructor now requires a uniqueidfor stable identity and folder naming.- Automatic folder hashing ensures storage isolation based on instance ID.
- Refined Static Key Factories: Renamed factories for brevity and consistency:
Keep.kInt,Keep.kIntSecureKeep.kString,Keep.kStringSecureKeep.kBool,Keep.kBoolSecureKeep.kDouble,Keep.kDoubleSecureKeep.kList,Keep.kListSecureKeep.kMap,Keep.kMapSecureKeep.custom,Keep.customSecure
Changed #
- Breaking:
Keepconstructor requires positionalid: String. - Breaking:
Keep.init()no longer acceptsfolderNameas it is now derived fromid. Keepinstances now perform automatic key binding during construction for multi-instance support.
0.4.0 #
Added #
- Version-Based Migration System: Introduced
KeepCodecarchitecture for seamless storage format upgradesKeepCodec.of(bytes)automatically selects correct codec based on version byteKeepCodecV1implements current JSON-based format with optimized header structure- Future-proof: Add new codecs without breaking existing data
- New binary format with version-first layout:
[Version][Flags][Type][Lengths...][Data] KeepCodecOfwrapper for automatic codec selection and decodingKeepHeaderclass for metadata extraction without full payload parsing
Changed #
- Breaking: Binary format updated - version byte moved to first position for instant detection
- Batch encoding/decoding moved from codec interface to internal storage implementation
- Simplified codec interface to single-entry operations only
Performance #
- Header parsing now O(1) instead of O(n) due to fixed-position metadata
- Codec selection happens once at read time, not per-operation
0.3.0+1 #
0.3.0 #
Changed #
- Breaking:
SubKeyManager.toList()now works without requiring a meta-file. - Breaking: Storage format updated. Old data will be treated as non-existent and ignored.
Added #
SubKeyManager.toList()now finds sub-keys even if they haven't been written yet in the current session.clearRemovable()can now remove all removable sub-keys, even those not accessed in the current session.
Fixed #
- Improved reliability of sub-key discovery across app restarts.
0.2.16 #
0.2.15 #
0.2.13 #
Added #
- Added
SubKeyEventenum (added,removed,cleared) for tracking sub-key changes. - Added
streamgetter toSubKeyManagerfor reactive sub-key monitoring. SubKeyManagernow extendsChangeNotifierfor Flutter widget integration.- Added
dispose()method toSubKeyManagerfor proper resource cleanup.
0.2.10 #
Fixed #
- Fixed race condition in
SubKeyManager._ensureInitialized()that could cause concurrent calls to run multiple_performLoad()operations. - Added
_ensureInitialized()call toSubKeyManager.remove()to prevent data loss. - Errors in
_performLoad()now properly complete the completer with error, preventing infinite waits.
0.2.9 #
0.2.8 #
Fixed #
- Added try-catch blocks to
KeepCodec.encodeAll,decodeAll, andencodePayloadmethods.
0.2.7 #
Fixed #
- Internal storage now deletes corrupted files on decode failure instead of deadlocking.
0.2.6 #
Fixed #
- Added missing try-catch blocks to
SubKeyManagerI/O operations. - Disabled
avoid_catches_without_on_clauseslint rule for broader exception handling.
0.2.5 #
Added #
- Added memory cache for
KeepKeyPlainandKeepKeySecureread operations. - Added
clear()andremove()methods toSubKeyManager.
Changed #
- Renamed
KeepValueTypetoKeepType. - Replaced
tUnknownwithtNulland addedtBytesforUint8Listsupport.
Performance #
- Read operations now return cached values, significantly improving throughput.
- See
test/stress_test.dartfor benchmarks.
0.2.3 #
Added #
- Added
KeepValueTypeenum for type-safe binary encoding. - Type byte now stored in binary format header.
- Added
KeepValueType.parse<T>()for default type conversions.
0.2.2 #
0.2.1 #
0.2.0 #
Added #
- Introduced binary format versioning and migration infrastructure (V1).
- Improved storage key hashing and internal data obfuscation.
Changed #
- Breaking:
KeepKeySecurenow stores raw encrypted values directly for better efficiency. - Standardized code structure and return patterns.
Fixed #
- Fixed crash when handling empty external storage files.
- Added legacy format support during migration.
0.1.2 #
0.1.1 #
0.1.0 #
Added #
- Added
fromStorage/toStorageconverters toKeepKeyPlain. - Enhanced type safety for
Keep.listandKeep.mapfactories.
0.0.2 #
Added #
- Added static key factories (
Keep.integer,Keep.stringSecure, etc.). - Added
decimalanddecimalSecurefactories.
Changed #
Keep.keysnow uses internal registry for faster access.clearRemovable()automatically notifies listeners.
Fixed #
- Improved
numtodoubleconversion. - Fixed boolean parsing support.
0.0.1+1 #
- Internal build stabilization.
0.0.1 #
- Initial release