dartvex_flutter 0.2.0
dartvex_flutter: ^0.2.0 copied to clipboard
Flutter widgets for Convex — ConvexProvider, QueryBuilder, MutationBuilder, and more. Reactive UI powered by Dartvex.
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.
[Unreleased] #
0.2.0 - 2026-06-12 #
Added #
ConvexClientRuntimenow preserves successful query log lines and maps real core optimistic query emissions tosource: cachewithhasPendingWrites: true.- Rich connection status:
ConvexRuntimeClientgainsconnectionStatus(aStream<ConnectionStatus>) andcurrentConnectionStatus, and the newConvexConnectionStatusBuilderrebuilds on the detailed status (inflight counts, retry count, loading,hasEverConnected).ConnectionStatusis re-exported fromdartvex. The coarseConvexConnectionBuilderandConvexConnectionIndicatorare unchanged. PaginatedQueryBuilderis now backed by the core reactive pagination engine: loaded pages update live as their data changes and stay gapless at page boundaries, instead of being one-shot reads. The widget API (query/builder/fromJson/args/pageSize/client) andPaginationStatusare unchanged.ConvexRuntimeClientgainspaginatedQuery(...)returning aConvexRuntimePaginatedQuery, andConvexPaginatedResult/ConvexPaginationStatusare re-exported fromdartvex.ConvexMutation.optimisticUpdateapplies an optimistic update while the mutation is in flight, overlaying query results instantly and rolling back when it completes or fails.ConvexRuntimeClient.mutatenow accepts an optionalOptimisticUpdate, andOptimisticLocalStore/OptimisticUpdate/OptimisticQueryEntryare re-exported fromdartvexfor convenience.ConnectivityPlusSignal, aconnectivity_plus-backedConnectivitySignal. Pass it toConvexClientConfig.connectivitySignalso the client reconnects immediately when the device regains network connectivity.ConvexAuthRefreshingBuilder, a widget that rebuilds with the client's auth-refreshing state (truewhile auth is being recovered after a server rejection).ConvexRuntimeClientnow exposesauthRefreshingandcurrentAuthRefreshing, backed byConvexClient.authRefreshing.ConvexRuntimeQueryLoading, emitted when the core client reports an optimistic query clear/loading state.- NSURLSession-backed network transports on iOS and macOS, installed
automatically at startup via Dart plugin registration
(
DartvexFlutterPlugin.registerWith()). All SDK network paths — the sync WebSocket, storage uploads, auth endpoints, asset-cache downloads, andConvexFileDownloader— now use the same system network path as Safari and native apps instead of rawdart:iosockets. POSIX sockets are discouraged by Apple (they bypass VPNs, proxies, and per-app network policy; see dart-lang/sdk#41376) and are blackholed witherrno 65on some iOS devices. Apps can opt out by resettingdefaultWebSocketAdapterOverrideanddefaultHttpClientFactorytonullearly inmain(), or override per client withConvexClientConfig.adapterFactory/ explicithttpClientparameters as before.installCupertinoTransport()is exported to re-install the defaults after an opt-out. Addscupertino_http,http,objective_c, andweb_socketdependencies; the package is now a Dart-only plugin on iOS/macOS. - The WebSocket transport uses a session-owning NSURLSession socket: the
URLSessioncreated for each connection attempt is invalidated once the connection ends. UpstreamCupertinoWebSocketnever invalidates its session, which leaks a native session per connect — a real cost for a sync client that reconnects indefinitely (dart-lang/http#1282). defaultWebSocketAdapterOverrideanddefaultHttpClientFactoryare re-exported fromdartvex_flutter, so the documented transport opt-out is reachable without a directdartveximport.
Changed #
- Requires
dartvex^0.2.0so web consumers resolve the current JavaScript-compatible value codec. - Requires Dart
^3.8.0and Flutter>=3.32.0, matching the minimums required by the Cupertino transport dependencies. - Clarifies in the README and API docs that disk-backed file/image cache
helpers (
ConvexAssetCache,ConvexCachedImage,ConvexOfflineImage, and progress-download image helpers) are native-only; web apps should render signed storage URLs directly. ConvexQuerynow renders loading when it receives an optimistic clear event, andhasDatarepresents a concrete query result even when that result is Convexnull.PaginatedQueryBuildernow uses the core paginated query's synchronous current snapshot on the first build, so warm remounts can render cached pages without a loading frame.
Fixed #
ConvexQueryandPaginatedQueryBuildernow compare rebuild arguments against the deep-snapshotted args used for the active subscription. Reusing aMapand mutating it in place between parent rebuilds now correctly resubscribes to the new query instead of leaving the widget attached to the previous args.- The NSURLSession WebSocket decodes peer close reasons with
allowMalformed. A close frame carrying invalid UTF-8 previously threw out of the session delegate callback, which skipped the close event entirely — leaving the sync layer blind to the disconnect until its inactivity timeout — and leaked the owned native session. The close reason is diagnostic-only, so replacement characters are harmless. - The NSURLSession WebSocket now turns unexpected receive/send errors into an abnormal close instead of throwing out of the async task callback, ensuring the owned session is invalidated and the sync layer sees a disconnect.
- The NSURLSession WebSocket adapter now converts raw
socket.eventsstream errors into abnormal close events and cleans up the socket best-effort, instead of letting those errors escape the zone before the core reconnect manager can handle them. ConvexProviderno longer lets the disposed-client error escape into the Flutter lifecycle dispatch when the app resumes after an externally owned client (disposeClient: false) was disposed in the background, including when that error is reported by the reconnect future after lifecycle dispatch returns. The best-effortAppResumedreconnect is skipped instead.- Inline closures no longer reset widget state on parent rebuilds:
decode(ConvexQuery,ConvexMutation,ConvexAction),fromJson(PaginatedQueryBuilder), andoptimisticUpdate(ConvexMutation) are treated as render/call-time mappings instead of subscription identity. Previously a parent rebuild that passed a new closure instance resubscribed the query, reset a paginated list back to its first page, or wiped the request snapshot. Changingdecode/fromJsonnow re-decodes the current value (or re-maps the loaded items) in place. ConvexMutation/ConvexActionno longer surface unhandled zone errors when the returned future is ignored (the normal builder pattern), both for the in-flight guard and for request failures already reported through the snapshot. Awaiting callers still receive the same errors.FakeConvexClient.dispose()no longer throws aConcurrentModificationErrorwhen a subscription listener reacts to its done event by canceling a subscription (done events are delivered synchronously while dispose closes the fake's controllers).- The NSURLSession WebSocket adapter decodes binary frames with
allowMalformed, so a peer sending invalid UTF-8 can no longer throw an uncaughtFormatExceptionout of the socket listener. The garbled message fails JSON parsing upstream instead, driving the normalInvalidServerMessagereconnect. ConvexImageandConvexCachedImagenow treat a changed runtime client as a new load identity, preventing stale images from a previous provider/client and avoiding implicit retries when unchanged failed loads rebuild.- Reactive query and paginated-query widgets now ignore late events from canceled subscriptions after inputs change, preventing stale results from overwriting the newest subscription state.
- Raw errors emitted by custom runtime query or paginated-query streams are now mapped into widget error state instead of escaping as unhandled Flutter stream errors.
- Action and mutation builders now ignore stale in-flight completions after their action/mutation or client changes, so old results cannot overwrite the new request state.
FakeConvexClientnow broadcasts duplicate query subscriptions and paginated queries with the same name to every live handle instead of only the latest.FakeConvexClientnow deep-snapshots query, subscription, mutation, and action arguments before invoking handlers, matching the real client behavior and preventing caller-side map mutations from changing deferred fake results.- Closes file-download HTTP clients and rejects non-success responses instead of returning error bodies as image bytes.
ConvexFileDownloader.downloadnow applies a configurableidleTimeout(default 30s) to connecting, awaiting response headers, and the gap between body chunks, so a stalled server fails with aTimeoutExceptioninstead of leavingConvexImageloading forever with an open HTTP client. It is an idle (inter-event) bound, so large downloads that keep progressing are never cut off.- Ignores stale async image/cache loads after widget inputs change.
- Resets paginated queries when query inputs or client instances change.
- Returns failed futures for overlapping action/mutation requests instead of throwing synchronously.
- Preserves structured query error data and server log lines in runtime errors.
- Supports action-based storage URL resolvers in
ConvexImageandConvexCachedImage. - Normalizes malformed storage URL resolver results in
ConvexImageandConvexCachedImagetoConvexStorageException, instead of surfacing raw cast errors for non-string values. - Excludes build artifacts from the package archive.
ConvexAssetCache.dispose()now closes the HTTP client the cache created for its file service (CacheManager.dispose()never does), releasing its platform resources — an NSURLSession on iOS/macOS.ConvexFileDownloader.downloadnow bounds draining a non-2xx error response body byidleTimeout, so a stalled error response fails with the status error instead of hanging the download forever.
0.1.4 - 2026-04-30 #
0.1.3 - 2026-03-22 #
Added #
ConvexRuntimeClient.reconnectNow(String reason)— propagate reconnect to the Flutter runtime layer.- App lifecycle listener in
ConvexProvider— automatically forces a reconnect when the app resumes from background if the connection is not active.
0.1.2 - 2026-03-21 #
Improved #
- Added comprehensive dartdoc comments on all public API
- Added example file for pub.dev scoring
0.1.1 - 2026-03-21 #
0.1.0 - 2026-03-15 #
Added #
- ConvexQuery reactive widget for query subscriptions
- ConvexMutation widget for executing mutations
- ConvexAction widget for action invocation
- ConvexProvider for dependency injection
- ConvexConnectionBuilder and ConvexConnectionIndicator
- ConvexAuthProvider and ConvexAuthBuilder
- ConvexImage widget for displaying storage images
- PaginatedQueryBuilder for cursor-based pagination
- FakeConvexClient test helper for testing
- ConvexOfflineImage with asset caching
- ConvexAssetCache for offline binary asset caching
- Runtime-interface based integration via ConvexClientRuntime
- Widget tests, example app, and package documentation