firewatch 1.10.3
firewatch: ^1.10.3 copied to clipboard
Lightweight Firestore repositories for Flutter: single-doc, collection, and collection-group repos that react to auth, stream updates, and support live-window pagination.
Changelog #
1.10.3 #
Fixed #
-
loadMore()is no longer silently dropped when called while a previous window resize is still settling (a rapid second tap, or aloadMoreduring an auth/dependency settle). The growth is now coalesced and applied once the in-flight resize completes. Affects both the collection and collection-group repos. -
hasMoreis nowfalsewhenpaginate: false. Previously a non-paginated repo with more documents thanpageSizelefthasMorestucktrue, even though the snapshot already held the full result set andloadMore()did nothing useful. -
FirestoreDocRepository.readyno longer hangs when the repo is disposed before its first load completes.dispose()now completes thereadyfuture (with the current value) so a pendingawait repo.readyresolves instead of awaiting forever. -
notifierFor(key)now returns a stable instance that keeps updating across page-window changes. Previously, when an item left the live window its per-item notifier was discarded and a new instance was created if the item reappeared, so a detail view holding the reference silently stopped updating. The notifier is now seeded from the cache, goesnullwhen the item leaves the window, and updates again when it re-enters. (The notifier map is also bounded by the keys callers actually request — it no longer auto-creates one per document.)
Docs #
- Clarified that
FirestoreDocRepositorywrite Commands resolve the target document path from the current auth UID at write time — don't hold and replay a write across an auth change (a model captured as user A, written after switching to user B, lands at B's path). - Security: documented that collection-group queries must be scoped by
owner/uid (e.g.
.where('ownerId', isEqualTo: uid)). The repo passesuidbut adds no filter itself, so an unfiltered builder reads other tenants' documents (README + class doc). - Batch atomicity: documented that batch writes are atomic per 500-op chunk only — longer lists commit as multiple sequential batches and are not all-or-nothing (corrected the package overview's "atomic" wording).
- Caching: documented the cache-first staleness behavior — after a cache
hit, a failed server read leaves the stale cached value on screen (surfaced
via
onError, not reverted).
1.10.2 #
Changed #
- Internal: the collection and collection-group repos now share a single
lifecycle base (
QueryListRepositoryBase), and all three repos share the auth / epoch / subscription primitives (AuthReactiveLifecycle). This removes the duplicated swap / cache-prime / window-resize / snapshot / dispose logic that had drifted between the collection and collection-group repos — the very drift that required the 1.10.1 fixes — so that class of bug can no longer recur. No public API changes.
Fixed #
- Collection-repo pagination (
loadMore) stream errors now suppress errors from a detached (signed-out) repo, matching the primary listener and the collection-group repo.
1.10.1 #
Fixed #
FirestoreCollectionGroupRepositorysafety parity with the doc and collection repos. Three guards that shipped for the sibling repos (in 1.5.1 and 1.8.1) were never ported to the collection-group repo:dispose()now increments the epoch before tearing down, so an in-flight_swap(e.g. one awaiting a cache read) can no longer write to the disposed notifiers. Previously this could throw "A ValueNotifier was used after being disposed" or silently repopulate a disposed repo.- Sign-out now awaits the listener cancel before returning, so the
native Firestore listener is fully torn down before the auth token is
invalidated (prevents a
PERMISSION_DENIEDerror loop on sign-out). - The stream
onErrorcallbacks now suppress errors when the repo is auth-detached (signed out), matching the collection repo, so a dying listener can't surface a spurious permission error toonError.
1.10.0 #
Added #
refresh()onFirestoreDocRepository. A public method to force a re-read of the document using the current auth state, mirroring the existingFirestoreCollectionRepository.refresh(). For one-shot repos (subscribe: false) this is how you pick up out-of-band changes (another device, a Cloud Function, a webhook): call it on app resume, on pull-to-refresh, or after a local write. The refetch happens in place, keepingvalueandhasInitializeduntil fresh data arrives, so no loading / uninitialized state flashes over the already-loaded document.
Fixed #
- One-shot
FirestoreDocRepositorynow clearsvaluewhen arefresh()finds the document deleted, matching the live-listener path (previously a stale value lingered).
1.9.0 #
Added #
- Partial upsert on
FirestoreDocRepository(#19).- New Command
setFields(Map<String, dynamic>)— likepatch, but usesset(..., SetOptions(merge: true))so the document is created if it doesn't exist. Use this for opt-in flows, default-setting writes, or any partial write where the doc may not have been initialized yet. - Existing
patchkeeps itsupdate()semantics (throwsnot-foundon missing doc) for callers that rely on that.
- New Command
- Direct writes on
FirestoreDocRepository, mirroring the existingFirestoreCollectionRepositoryDirect API:writeDirect(T)—set(merge: true)with full modelupdateDirect(T)— full-model update (throws if missing)patchDirect(Map)— partial update (throws if missing)setFieldsDirect(Map)— partial upsert (create if missing)deleteDirect()— delete- Use these when you need to fire rapid, overlapping writes that would otherwise be rejected by the Command single-execution guard.
1.8.1 #
Fixed #
- Sign-out race with snapshot retry loop (#17): On sign-out, the
subscription cancel was fire-and-forget, so the native Firestore listener
could fire
PERMISSION_DENIEDerrors before the Dart-side cancel reached the native layer. Combined with the retry mechanism from 1.8.0, this created an error loop. The null-UID path in_swap()now awaits the subscription cancel, andonErrorsuppresses retries when the repo is auth-detached.
1.8.0 #
Added #
- Automatic retry on snapshot listener errors. When a Firestore snapshot
listener dies (e.g.
PERMISSION_DENIEDbecause a parent document hasn't been committed server-side yet), the repository now retries with linear backoff instead of leaving the listener permanently dead. - New
FirestoreCollectionRepositoryconstructor parameters:maxRetries(default: 5) — number of retry attempts before giving up.retryDelay(default: 500 ms) — base delay, multiplied by attempt number (500 ms, 1 s, 1.5 s, 2 s, 2.5 s).
- Retry counter resets on successful snapshot or on auth/dependency/query
change. After
maxRetriesexhausted, the repo settles intohasInitialized = true/isLoading = false(previous behavior).
Fixed #
- Race condition where subcollection repos activated before their parent
document was server-confirmed during first-time anonymous sign-in. The
snapshot listener would hit
PERMISSION_DENIEDand die permanently — writes went through to Firestore but the UI never updated.
1.7.1 #
Changed #
- Updated README with documentation for direct write methods, error handling
table, and
onErrorcallback usage example. - Added one-shot
_resizeWindowcoverage tests for both collection repository types.
1.7.0 #
Added #
onErrorcallback on all three repository constructors (FirestoreDocRepository,FirestoreCollectionRepository,FirestoreCollectionGroupRepository). Called with the error and stack trace when a Firestore snapshot listener or one-shot fetch fails. Optional and non-breaking — when omitted, existing behavior is unchanged.FirewatchErrorHandlertypedef exported fromfirewatch.dartfor typing the callback:void Function(Object error, StackTrace stackTrace).
1.6.0 #
Added #
- Direct write methods on
FirestoreCollectionRepository:addDirect,setDirect,patchDirect,updateDirect,deleteDirect. These bypass theCommandsingle-execution guard, allowing concurrent writes to different documents in the same collection. Use them when rapidly editing multiple items (e.g. toggling checkboxes in a list) where the Command-based methods would silently drop overlapping calls. - Direct write methods on
FirestoreCollectionGroupRepository:setDirect,patchDirect,updateDirect,deleteDirect. Same concurrent-safe semantics for collection group repositories. - Existing Command-based CRUD (
patch,set,update,delete,add) remains unchanged for use cases that benefit fromisRunning/errorsobservability.
1.5.2 #
Fixed #
- In-flight async ops update disposed notifier (#15):
FirestoreCollectionRepository.dispose()did not increment the epoch counter, so pending cache primes, snapshot callbacks, or one-shot fetches could write to already-disposedValueNotifiers (causing Flutter assertion errors). Now mirrorsFirestoreDocRepository.dispose()by bumping_epochfirst.
1.5.1 #
Fixed #
readyreturns stale null afterauthUidchange (#13):_readyCompleterwas never reset, soreadycached its first result forever. NowhasInitializedresets tofalseand a freshCompleteris created on every auth transition, so callers re-await fresh data.
1.5.0 #
Added #
- Batch CRUD operations on
FirestoreCollectionRepository:batchAdd,batchSet,batchPatch,batchUpdate,batchDelete. All areCommandinstances (not plain Futures), so consumers can watchisRunning, listen toerrors, and use the full Command lifecycle — consistent with single-item CRUD commands. - Automatically chunks operations at the Firestore 500-operation batch limit.
- Auth-gated: batch commands route a
StateErrorthrough.errorswhen the UID is null, matching single-item command behavior.
1.4.0 #
Added #
hasInitialized(ValueNotifier<bool>) onFirestoreDocRepository— flips totrueafter the first successful load (from cache or server) and never reverts. Mirrors the existing property onFirestoreCollectionRepository.ready(Future<T?>) onFirestoreDocRepository— completes with the first loaded value (which may benullif the document doesn't exist). Useful for one-timeawaitin services that need data before proceeding.
Fixed #
dispose()now increments the epoch counter to prevent in-flight async operations from writing to a disposed notifier.
1.3.1 #
Fixed #
- Web compatibility:
parentIdinjection no longer crashes on web.cloud_firestore_webthrows an Expando error when calling.parenton a top-levelCollectionReference(where the parent isnull). The newparentIdOf()helper wraps the call in a try-catch, returningnullfor top-level collections.
1.3.0 #
Added #
parentIdis now automatically injected into the data map before callingfromJsonacross all three repository types. Models can opt-in by declaring aparentIdfield in theirfromJsonfactory — no changes toJsonModelrequired. Particularly useful for collection group queries where documents with the same ID can live under different parents.
1.2.0 #
Added #
FirestoreCollectionGroupRepository<T>— reactive queries across all subcollections with the same name via FirestorecollectionGroup(). Supports live pagination, per-item notifiers keyed by full document path, and path-based CRUD (set,update,patch,delete).QueryRefBuildertypedef andGroupPatchrecord type for collection group write operations- Updated README with collection group examples
Fixed #
FirestoreDocRepositorystream subscription now has anonErrorhandler. Previously a stream error (permission denied, network failure) would leaveisLoadingstuck attrueforever.
1.1.0 #
Added #
- Repositories now work without
authUidfor public/unauthenticated collections (e.g.static/config). OmittingauthUidqueries Firestore immediately instead of waiting for a signed-in user. - Updated doc comments with public-collection usage examples
1.0.0 #
- Stable release — no API changes, just documentation polish
- Added doc comments to all public members across both repository types
0.3.0 #
Improved #
- Collection repo now primes UI from Firestore local cache before starting the live subscription, giving instant data on revisits
- Incremental snapshot processing via
docChanges— only re-parses added/modified/removed documents instead of deserializing the full list on every snapshot event - Per-item notifiers are now pruned (removed from the map) when documents leave the snapshot, preventing unbounded memory growth over long sessions
0.2.0 #
Breaking #
- Bumps
command_itfrom ^8.0.0 to ^9.0.0 - Requires Dart >=3.8.0 and Flutter >=3.32.0
writecommand onFirestoreDocRepositoryno longer accepts an unreachablemergeparameter (always merges)
Fixed #
- Race condition in
FirestoreDocRepository._swapon rapid auth changes (added epoch guard) _resizingflag inFirestoreCollectionRepositorycould get permanently stuck, breakingloadMore()- Deleted documents now correctly clear
valuetonullinFirestoreDocRepository - Pagination limit now resets on query/dependency changes
- Per-item notifiers are nulled out when documents leave the snapshot
- All
Commandobjects are now properly disposed
Improved #
- Bumps
cloud_firestoreto ^6.0.0,flutter_lintsto ^6.0.0 - Fixes CI docs workflow (uses stable Flutter channel, gh-pages v4)
- Test coverage increased from 4 to 26 tests (94% line coverage)
0.1.4 #
- Adds
paginateoption toFirestoreCollectRepositoryto enable pagination of collection queries
0.1.3 #
- Improves example and README
0.1.2 #
- Formatting issue
0.1.1 #
- Adds better documentation, examples, and updates licence
0.1.0 #
- Initial release: single-doc and collection repositories
- Live-cache prime, metadata-churn squash
- Live-window pagination, per-item notifiers
- Simple CRUD commands