syncache 0.2.0
syncache: ^0.2.0 copied to clipboard
An offline-first cache and sync engine for Dart with optimistic mutations, reactive streams, and pluggable storage.
Changelog #
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
0.2.0 #
BREAKING CHANGES #
- Invalidation no longer closes watch streams.
invalidate,invalidateTag,invalidateTags,invalidatePattern, andclearused to close the affected watchers' streams (aCacheBuilderlanded inConnectionState.doneand never recovered). Invalidation now refetches each affected watcher with the fetch/policy/ttl it was created with: fresh data is emitted on success, the error is emitted as a stream error on failure (the stream stays open), andPolicy.cacheOnlywatchers receive aCacheMissExceptionwithout closing. Listeners keep the last value until the refetch completes (stale-while-invalidated).ConnectionState.donenow only occurs when every listener unsubscribes or the cache is disposed. Code that relied on a stream'sonDonefiring after invalidation must be updated. mutate()returnsFuture<MutationHandle<T>>(previouslyFuture<void>). Plainawait cache.mutate(...)call sites keep compiling; only code that explicitly typed the result is affected. The handle resolves with a sealedMutationOutcome:MutationSuccess(serverValue),MutationFailure(error, stackTrace, retried), orMutationDiscarded.clear()gains an optionalrefetchWatchersparameter (defaulttrue, so existing calls keep refetching — which is the new behavior instead of closing streams). Passclear(refetchWatchers: false)for silent bulk wipes. The flag is also available onclearScopeandScopedSyncache.clear.ReactiveNetworkadded to core. ANetworkthat also exposesonConnectivityChanged. CustomNetworkclasses are unaffected; see below.
Added #
- Automatic mutation flush on reconnect. When the provided
networkis aReactiveNetwork,Syncachesubscribes to its connectivity changes and processes pending mutations as soon as the device is back online — no newmutate()call required. Queued mutations are no longer only processed when the next mutation is enqueued. Syncache.processPendingMutations()— force a queue pass manually (idempotent while a pass is running or the network is offline).Syncache.removePendingMutation(String id)— remove a specific queued mutation by itsPendingMutationInfo.id; the mutation's handle settles withMutationDiscarded.removeFirstPendingMutation()is deprecated in favor of this.MutationHandle/ sealedMutationOutcome(MutationSuccess,MutationFailure,MutationDiscarded) — await a specific mutation's server confirmation, retry exhaustion, or removal.- Seeded queue streams:
pendingMutationsStreamandisSyncedStreamnow emit their current state to every new listener before live updates, so late subscribers (e.g. a sync indicator built after mutations were queued) see the present state immediately. Syncache.clearScope/ScopedSyncache.clearacceptrefetchWatchers.
Fixed #
- Removing an in-flight mutation (via queue control) no longer makes the processing loop drop the next queued mutation on completion — mutations are now removed by identity instead of by position.
0.1.2 #
Fixed #
mutateListItemwithupdateWherenow sends the item matching the predicate (previously it sent the first item of the list and never evaluated the predicate)mutateListItemwithremoveWherenow callssendonce per removed item, deduplicated byidSelector(previously the server call was silently skipped)- Plain
writenow preserves existing tags on allTaggableStoreimplementations — behavior was previously inconsistent betweenMemoryStore/SharedMemoryStore(preserve) andHiveStore(clear). The contract is now documented onTaggableStore: plainwritepreserves tags,writeWithTagsreplaces them CacheMissForConditionalExceptionis now exported from the public API and extendsCacheMissException, so conditional cache misses can be caught with a singleon CacheMissExceptionclauseScopedSyncache.prefetchnow passes throughPrefetchRequest.retry- Documentation: fixed the
Network,RetryConfig, andSyncacheObserverexamples; policy table now includescacheAndRefresh
Added #
ScopedSyncache.setandScopedSyncache.watchWithDependenciesScopedSyncache.prefetchOneaccepts aretryparameter- Shared
TaggableStoreconformance suite covering tag lifecycle semantics - Tests for
getConditional(conditional headers, 304 handling, cache-miss behavior)
0.1.1 #
- Add
Policy.cacheAndRefresh- returns cached data immediately and always refreshes in background (unlikestaleWhileRefreshwhich only refreshes when expired)
0.1.0 #
- Initial release
- Core caching with five policies: offlineFirst, cacheOnly, networkOnly, refresh, staleWhileRefresh
- Reactive streams via
watch()andwatchWithMeta() - Optimistic mutations with automatic background sync
- Tag-based cache invalidation
- Pattern-based cache invalidation (glob support)
- Request deduplication for concurrent fetches
- Retry with exponential backoff
- Cancellation token support
- Scoped caches with key prefixing
- Parallel and dependency-graph prefetching
- Observer pattern for logging and analytics
- MemoryStore and SharedMemoryStore implementations