pocketbase_drift 0.3.15
pocketbase_drift: ^0.3.15 copied to clipboard
A powerful, offline-first PocketBase client backed by a drift database.
0.3.15 #
New Features #
- Configurable Sync Retry Count - Added
localSyncRetryCountparameter to$PocketBaseand$PocketBase.database(default: 5). This allows developers to control how many times a record update/create should be retried before being considered permanently failed.
Bug Fixes #
- Robust Handling of Stuck Records - Resolved an issue where records suffering from validation errors (including "orphaned" records referencing deleted parents) would retry indefinitely, causing battery drain and blocking the sync queue.
- All
400 Bad Requesterrors (validation failures, orphans, etc.) now increment a retry counter on the local record. - Once the
localSyncRetryCountis exceeded, the local record is automatically deleted to unblock the sync queue. - Useful for cleaning up local state that has become invalid relative to the server (e.g., a local comment on a post that was deleted on the server).
- All
0.3.14 #
Bug Fixes #
-
Fixed
clearAllData()also clearing the schema cache - TheclearAllData()method was incorrectly deleting all records from theservicestable, including the cached collection schema (stored withservice = 'schema'). This caused issues when the app tried to use schema-dependent features after clearing user data. The method now preserves schema records while clearing all other data. -
Improved connectivity restoration detection - The
connectivity_pluspackage doesn't reliably detect when network connectivity is restored, especially on iOS Simulator. The connectivity service now uses a hybrid approach:- Platform detection: Uses
connectivity_plusfor detecting when the device goes offline - Request-based detection: Network request success/failure is now reported to the connectivity service
- When a network request succeeds after being marked offline, connectivity is immediately restored
- After 2 consecutive network failures, the device is marked as offline
- Explicit
checkConnectivity()calls (e.g., on app resume) trust the platform status directly
- Platform detection: Uses
Improvements #
- Added
shouldAttemptNetworkgetter toConnectivityService- Returnstrueif the platform reports a network interface is available, regardless of recent request success. Use this for deciding whether to TRY a network request. UseisConnectedfor UI display or pessimistic decisions. - Added
reportNetworkSuccess()andreportNetworkFailure()methods toConnectivityServicefor request-based connectivity tracking - All network request decisions now use
shouldAttemptNetworkinstead ofisConnected, allowing the app to discover connectivity restoration by actually trying requests when the platform reports a network interface is available
0.3.13 #
Bug Fixes #
-
Fixed file field names being null when saving offline - Resolved a critical issue where creating or updating a record with files while offline (using
cacheAndNetworkpolicy) would result in file field names being saved asnullor empty in the local database. The_prepareCacheOnlyBody()method is now called before network attempts, ensuring file field names and blobs are properly cached regardless of network availability. -
Fixed files not syncing to server on connectivity restore - Files attached to records created offline were not being uploaded when connectivity was restored and
retryLocal()ran. The sync mechanism now:- Retrieves cached file blobs from the local database
- Identifies file fields from the collection schema
- Includes files as
MultipartFileattachments when syncing pending creates/updates to the server - Added
getFilesForRecord()method to the database for retrieving all cached files for a record
-
Improved file retrieval fallback behavior - File retrieval now follows the "stale data is better than no data" principle for offline-first apps:
cacheOnlywith expired cache: Now returns the expired cached file instead of throwingcacheAndNetworkwith expired cache + network failure: Now falls back to returning the expired cached file instead of throwing a network errorcacheOnlywith no cache: Now throws a descriptive error message- Added informative logging for cache expiration and fallback scenarios
Tests #
- Added 3 new tests for offline file creation with network failure simulation
- Added 1 test for file sync on connectivity restore
- Added 3 tests for file retrieval fallback behavior
0.3.12 #
New Features #
- Global Request Policy - Added a
requestPolicyparameter to the$PocketBaseclient that sets a default policy for all service methods. This allows you to configure the offline-first behavior globally instead of passing it to every method call.- Defaults to
RequestPolicy.cacheAndNetwork - Can be overridden per-call by passing an explicit
requestPolicyto any method - All method
requestPolicyparameters are now nullable (omit to use the global default)
- Defaults to
Bug Fixes #
- Fixed duplicate record creation with realtime subscriptions - Resolved a critical issue where creating a record with
RequestPolicy.cacheAndNetworkwhile usingwatchRecords()or other realtime subscriptions could result in duplicate records being created locally. This occurred when PocketBase ignored/replaced the client-provided ID (e.g., due to custom hooks) and generated its own ID. The code now detects ID mismatches between the sent and received ID, and uses the server's ID to prevent duplicates.- Added ID mismatch detection in
_createCacheAndNetwork - Added ID mismatch handling in
_tryCreateOnServerfor background sync - A warning is now logged when the server doesn't use the provided ID
- Added ID mismatch detection in
0.3.11 #
Bug Fixes #
- Fixed single-select validation and expansion - Resolved an issue where
select,file, andrelationfields were incorrectly treated as multi-select (lists) when theirmaxSelectschema option was set to0ornull. Per PocketBase documentation,maxSelect <= 1(including 0/null) indicates a single value (String), whilemaxSelect >= 2indicates multiple values (List). This fix ensures that fields with default or explicit 0/1maxSelectare correctly validated and returned as single strings, preventing "Field must be a list" errors.
Dependencies #
- Updated
pocketbaseto v0.23.1 - Includes a fix for the "all-in-one" OAuth2 flow that prevented successful re-authentication after a failed attempt.
0.3.10 #
New Features #
-
Enhanced Filter Parser - Major improvements to the filter parser for better PocketBase compatibility and new operators:
Literal Type Support:
nullliteral -field = nullnow correctly translates toIS NULLin SQLite- Boolean literals -
field = trueandfield = falseare now supported - Numeric literals - Unquoted numbers like
score > 100orprice = 19.99are handled correctly
"Any-of" Operators for Multi-Value Fields:
?=,?!=- Any element equals/not equals?>,?>=,?<,?<=- Any element comparison?~,?!~- Any element LIKE/NOT LIKE- Example:
tags ?= "flutter"checks if any tag equals "flutter"
DateTime Macros:
@now- Current UTC datetime@todayStart,@todayEnd- Day boundaries@yesterday,@tomorrow- Relative dates@monthStart,@monthEnd,@yearStart,@yearEnd- Period boundaries@second,@minute,@hour,@day,@weekday,@month,@year- Time components- Example:
created >= @todayStart && created <= @todayEnd
Field Modifiers:
:lower- Case-insensitive comparison usingLOWER():length- Array length check usingjson_array_length()- Example:
name:lower = "john"ortags:length > 2
Comment Stripping:
- Single-line comments (
// comment) are now stripped before parsing
Bug Fixes #
- Fixed date format mismatch causing incorrect sorting - Resolved an issue where records stored via
setLocalandmergeLocal(used by realtime subscriptions and batch syncs) would have theircreated/updatedtimestamps re-formatted, replacing the ISO 8601Tseparator with a space. This caused string-based sorting to produce incorrect results when mixed with records stored via$createwhich preserved the original format. All methods now preserve the original timestamp format from the server. (#8)
Improvements #
- Comprehensive test suite - Added 49 new tests covering all filter parser features
0.3.9 #
New Features #
- Batch Requests with Offline Support - Added
$createBatch()method for executing transactional batch operations with full offline-first support.- Queue multiple create, update, delete, and upsert operations across collections
- Execute all operations in a single HTTP request to PocketBase
- Full
RequestPolicysupport for controlling online/offline behavior - When offline or on failure with
cacheAndNetwork, operations are stored locally and retried as individual operations when connectivity is restored
0.3.8 #
New Features #
- Nullable Cache TTL - The
cacheTtlparameter in$PocketBase.database()is now nullable. Setting it tonulldisables automatic cache cleanup, allowing data to be persisted indefinitely. - Support for
updatedAt/createdAtfields - Added automatic fallback support for PocketBase applications that useupdatedAtandcreatedAtfield names instead of the defaultupdatedandcreated. This ensures that cache TTL cleanup, version comparisons, and local data storage work correctly regardless of the timestamp naming convention used. - Configurable Logout Cleanup - Added
clearOnLogoutparameter to$AuthStore(default:true). Developers can now set this tofalseto preserve local data when the user logs out, improving the experience for offline-first applications where re-fetching data might be expensive.
Bug Fixes #
- Fixed Connectivity & Cache Issues on Re-login - Resolved a critical issue where logging out and back in would cause connectivity to report incorrectly and cached streams to stop responding.
ConnectivityServiceis now a true singleton that is never disposed, matching the behavior ofconnectivity_plus's globalConnectivity()singleton. This prevents instability when recreating client instances.- Simplified database connection by removing manual isolate spawning, using Drift's built-in connection handling instead.
- Note for developers: If using Riverpod, invalidate your
pocketBaseProviderafter logout to ensure all dependent providers are refreshed with the new client instance.
0.3.7 #
Bug Fixes #
- Fixed nested expanded records not being cached - When fetching records with nested expand, the related records are now automatically cached to their respective collection tables. This enables local expand to work correctly when those collections are later queried independently.
- Previously,
mergeLocal(used bygetFullList) bypassed the caching logic, causing expanded records to be missing from the local cache. - The fix also applies recursively, so deeply nested expands are properly cached at all levels.
- Previously,
Tests #
- Added
expand_cache_test.dartwith 4 tests validating nested expanded record caching behavior.
0.3.6 #
BREAKING CHANGE: Local relation expansion now matches PocketBase SDK behavior.
Breaking Changes #
- Single relations now return objects directly - Previously, all expanded relations were wrapped in a list, requiring index access (e.g.,
expand.author.0.name). Now, single relations (maxSelect == 1) return the object directly, matching the official PocketBase SDK behavior:- Before:
record.get<String>('expand.author.0.name') - After:
record.get<String>('expand.author.name') - Multi relations (
maxSelect > 1) still return lists and require index access
- Before:
Migration Guide #
If you were accessing single relation expands with .0 index, remove the index:
// Before (0.3.5 and earlier)
final authorName = post.get<String>('expand.author.0.name');
final author = post.get<RecordModel>('expand.author.0');
// After (0.3.6+)
final authorName = post.get<String>('expand.author.name');
final author = post.get<RecordModel>('expand.author');
Multi-relation access remains unchanged:
final firstTag = post.get<String>('expand.tags.0.name'); // Still uses index
0.3.5 #
Documentation #
-
Expanding Relations Guide - Added comprehensive documentation for accessing expanded relations using the PocketBase SDK's
record.get<T>()dot-notation path syntax (e.g.,record.get<String>('expand.author.0.name')). Covers basic expansion, nested (multi-level) expansion, and multi-relation access patterns. -
Advanced: Direct Database Access - Added new documentation section explaining how to access the underlying Drift database directly via
client.dbfor advanced use cases:- Database schema overview (tables, columns, primary keys)
- Running raw SQL queries with
customSelect - Joining data across collections
- Reactive streams with raw SQL using
.watch() - Executing raw statements with
customStatement - Using the built-in
$querymethod
Tests #
- Added
expand_dot_notation_test.dartwith 8 comprehensive tests validating that locally expanded relations work correctly with the PocketBase SDK's dot-notation path access API.
0.3.4 #
New Features #
- Cache TTL & Expiration - Added configurable time-to-live (TTL) for cached data. Old synced records and cached responses are automatically cleaned up when
runMaintenance()is called.- Configurable
cacheTtlparameter in$PocketBase.database()(default: 60 days) - New
runMaintenance()method to clean up expired cache data - Returns
MaintenanceResultwith counts of deleted items - Only removes synced data - unsynced local changes are always preserved
- Cleans up expired file blobs automatically
- Configurable
0.3.3 #
New Features #
- Filter-aware sync for deleted records - Added
syncLocalmethod that intelligently syncs deletions from the server to local cache. When fetching data withgetFullList, the system now detects and removes records that were deleted on the server while offline, even when using filtered queries. This ensures local cache stays in sync with server state.- Works with both filtered and unfiltered queries
- Only deletes records within the filter scope
- Preserves unsynced local changes, local-only records, and pending deletions
- Includes safety check to prevent mass deletion on server errors
Improvements #
- Enhanced
getFullListbehavior - Now automatically callssyncLocalafter fetching all pages, ensuring deleted records are cleaned up from local cache - Added comprehensive test coverage - New test suite (
sync_local_test.dart) with 7 tests covering all edge cases for filter-aware deletion - PocketBase-compatible ID generation - Local IDs are now generated using PocketBase's exact format (
[a-z0-9]{15}). This eliminates the need for ID remapping during sync, simplifying the offline-first flow:- Records created offline now sync with the same ID they were created with
- Removed
shortiddependency in favor of a built-in secure random generator - Exported
newId()function for use by consuming applications
Bug Fixes #
- Fixed partial update validation for offline scenarios - Partial updates now correctly merge with existing record data before validation, allowing updates with only changed fields when using
cacheFirstorcacheOnlypolicies - Fixed SQLite quote semantics in filters - Added automatic quote normalization in filter parser to convert double quotes to single quotes for string literals, preventing SQLite from misinterpreting values as identifiers. Both
'id = "$id"'and"id = '$id'"now produce correct SQL
0.3.2 #
Bug Fixes #
- Critical: Fixed pending sync execution on app restart - Resolved a critical issue where pending changes would not sync when the app was completely closed and reopened. The sync mechanism now queries the database to identify services with pending records instead of relying on an in-memory cache that gets cleared on app restart. This ensures that all offline changes are reliably synced when connectivity is restored, even after a complete app restart.
0.3.1 #
- Resolved pub.dev issue
0.3.0 #
BREAKING CHANGES: Added new RequestPolicy options for more explicit control over caching and network behavior.
New Features #
- New RequestPolicy options: Added
RequestPolicy.cacheFirstandRequestPolicy.networkFirstfor more explicit control over data fetching and synchronization behaviorcacheFirst: Returns cache immediately, fetches network in background to update cachenetworkFirst: Tries network first, falls back to cache on failure (replaces oldcacheAndNetworkbehavior for reads)cacheAndNetwork: Now has distinct behavior - for reads it behaves likenetworkFirst, but for writes it provides resilient offline-first synchronization with automatic retry
Improvements #
- Refactored write operations (create/update/delete): Split monolithic methods into smaller, policy-specific implementations for better maintainability
- Enhanced documentation: Comprehensive guide on choosing the right
RequestPolicyfor different scenarios - Better error messages: More descriptive error messages that indicate which policy was used when operations fail
Write Operation Behavior Changes #
networkFirst(new strict mode): Writes to server first, updates cache on success, throws error on failure (NO cache fallback)cacheFirst(new optimistic mode): Writes to cache first, attempts server sync in backgroundcacheAndNetwork(enhanced): Tries server first, falls back to cache with pending sync on failure (maintains backward compatibility for offline-first apps)
Migration Guide #
Existing code continues to work - the default RequestPolicy.cacheAndNetwork maintains backward compatibility for most use cases.
However, if you were relying on specific behavior:
- If you want strict server-first writes with no offline fallback, use
RequestPolicy.networkFirst - If you want instant UI feedback with background sync, use
RequestPolicy.cacheFirst - If you want resilient offline-first behavior (old default), continue using
RequestPolicy.cacheAndNetwork
0.2.1 #
Exclude certain API paths from caching in send method
- Add a list of non-cacheable path segments to exclude specific API endpoints from being cached.
- Modify the send method to bypass cache if the request path contains any of these segments.
This prevents caching sensitive or system data like backups, settings, and logs.
0.2.0 #
Refactor file download methods to use consistent getFileData & Implement auto-generation of file token
- Change token parameter from bool to String?
- Add autoGenerateToken parameter to automatically generate tokens when needed
- Refactor file download methods to use consistent getFileData API across platforms
- Improve file service architecture to better handle token-based file downloads
0.1.2 #
- Update Documentation.
0.1.1 #
- Resolve pub.dev score issues e.g outdated plugin dependencies.
0.1.0 #
- Initial release.
This is the first version of pocketbase_drift, a powerful offline-first client for the PocketBase backend, built on top of the reactive persistence library Drift.
Features #
- Offline-First Architecture: Read, create, update, and delete records even without a network connection. The client seamlessly uses the local database as the source of truth.
- Automatic Synchronization: Changes made while offline are automatically queued and retried when network connectivity is restored.
- Reactive Data & UI: Build reactive user interfaces with streams that automatically update when underlying data changes, whether from a server push or a local mutation.
- Local Caching with Drift: All collections and records are cached in a local SQLite database, providing fast, offline access to your data.
- Powerful Local Querying: Full support for local querying, mirroring the PocketBase API. This includes:
- Filtering: Complex
filterstrings are parsed into SQLiteWHEREclauses. - Sorting: Sort results by any field with
sort(e.g.,-created,name). - Field Selection: Limit the returned fields with
fieldsfor improved performance. - Pagination:
limitandoffsetare fully supported for local data.
- Filtering: Complex
- Relation Expansion: Support for expanding single and multi-level relations (e.g.,
post.author) directly from the local cache. - Full-Text Search: Integrated Full-Text Search (FTS5) for performing fast, local searches across all your cached record data.
- Authentication Persistence: User and admin authentication state is persisted locally using
shared_preferences, keeping users logged in across app sessions. - Cross-Platform Support: Works across all Flutter-supported platforms, including mobile (iOS, Android), web, and desktop (macOS, Windows, Linux).
- Basic File & Image Caching: Includes a
PocketBaseImageProviderthat caches images in the local database for offline display. - Custom API Route Caching: Added support for offline caching of custom API routes accessed via the
sendmethod. This allowsGETrequests to custom endpoints to be cached and available offline, improving performance and reliability for custom integrations. - Robust & Performant: Includes optimizations for batching queries and file streaming on all platforms to handle large files efficiently.
Improvements #
- Improved maintainability by refactoring the large
createandupdatemethods in the internalServiceMixininto smaller, more manageable helper methods. - Improved web performance by switching from a full
http.get()to a streaming download for file fetching, aligning it with the more memory-efficient native implementation.