flutterflow_cloud 0.4.1
flutterflow_cloud: ^0.4.1 copied to clipboard
The FlutterFlow Cloud SDK for Flutter — typed database records and queries, end-user auth with self-contained persistent sessions, file storage with progress and URL caching, and a fast built-in proje [...]
Changelog #
0.4.1 #
- A refused watch (
permissionDenied, a model whosesubscribeisnone, an unknown query, the 100-watch limit) now ends only itself. Before, the SDK answered the refusal with anunsubscribethe server could only reject asunknownSubscriptionId, and that rejection ended every other watch in the app: each one emittednullor an empty list, failed and disconnected. - The query cache keeps the baseline
draft-0config identity a new project serves as a draft identity instead of reading it back as0.
0.4.0 #
- Add
collection(model).watch(id)and, in generated bindings, a typedwatch(id)on every collection: one record, then each change, or null while it is missing or hidden by the model's get or subscribe rule. Only that record's writes reach the watch. - Add named-query
watch(), typed snapshots and connection state. - Share equivalent watches and apply server-proven visible-row updates without redundant queries; uncertain changes retain strong first-page reconciliation.
- Multiplex WebSockets with strong first-page reconciliation, auth invalidation, bounded reconnect, cancellation and paused-listener coalescing.
- Support the same watch API through the offline emulator and preview proxy.
- Password reset:
cloud.auth.sendPasswordResetEmail(email: …)emails a reset link to an email/password account, andcloud.auth.completePasswordReset(oobCode: …, newPassword: …)sets the new password with the link's code, which revokes every session of that account. Neither signs anyone in or out locally.oobCodeInvalidandoobCodeExpiredareFFXValidationErrors. - Two tabs of a web app no longer sign each other out. Both hold the stored
session, and a tab that refreshed with the refresh token another tab had
already spent tripped the reuse check, which revokes the session. Now tabs
refresh one at a time under the Web Lock
ffx.<scope>.refresh(an isolate-local lock wherenavigator.locksis missing), and a refresh first takes a session another tab rotated since, presenting its refresh token only when its access token is due. - An expired App Preview ticket is never a sign-out. A
401 previewTicketExpiredre-reads the base URL the host renews and sends once more; a second refusal is anFFXServiceUnavailableError, and the session stays. A401 tokenExpiredwhose refresh failed transiently no longer clears the session in the background reconcile. - Inside App Preview, a screen preview that reads
FlutterFlowCloud.instancebefore anyinitializegets an instance the SDK connects itself, on the preview's backend with the whole-app preview's session or as a guest, instead ofFlutterFlowCloud has not been initialized. It borrows that shared session and never rotates its refresh token. The app's owninitializereplaces it. Outside App Preview nothing changes. - A
cloud.auth.deleteAccount()the server refuses for good (a 4xx problem the SDK does not retry, such as the403 permissionDeniedfor drip's test account) leaves the session as it was: its token, refresh and auth events carry on, and the next call is a new deletion with a new Idempotency-Key. Before, the session stopped refreshing until its token expired. A deletion started while a refresh is in flight waits for that refresh to land, so a refused one hands back the refreshed session, not a spent refresh token. A retry after a transport failure, a timeout, a 5xx, a 429 or a 409idempotencyKeyInUsestill keeps the original key.
0.3.0 #
cloud.connectors.call(connector, operation, params: …)calls an outside service the project connected (Slack, Resend, Stripe, OpenAI, Anthropic, Gemini, Airtable, Notion, …) through the platform, for an operation declared underconnectorsin.ffx/project.json; the app carries no key. Connector refusals areFFXApiErrors whoseuserMessageis written for the app's user, and an acting call that may have gone through (connectorOutcomeUnknown) is never retried. The generatedffx.dartre-exportsFFXConnectors.- Custom claims stay current: the SDK follows the account's auth events and refreshes the session when its claims change.
cloud.auth.deleteAccount()permanently deletes the signed-in account and revokes its sessions.- Requests share one time budget across retries, and a mutation retried after a transport failure keeps its original Idempotency-Key.
- Previews in FlutterFlow reach their own backend without app changes;
FFX_EMULATOR_URLpoints the emulator client at a full URL. - Breaking:
FFXPersistedSessionhas a requiredclaimsRevision. A session saved by 0.2.x does not restore, so a signed-in user signs in again once after the upgrade (and a guest starts as a new guest).
0.2.2 #
fileReferenced(deleting a file a record still points at) is anFFXConflictError.- Generated file collections gain
allowsContentType, and theuploadpre-flight accepts single-type wildcards (image/*) the way the platform does.
0.2.1 #
- Package README replaced with a short placeholder ahead of the public documentation.
0.2.0 #
The client SDK, rebuilt as a Flutter package. Replaces ffx_client 0.1.0
(package renamed; hard break, pre-release).
FlutterFlowCloud.initialize/FlutterFlowCloud.instancereplaceFFXApp; connection settings live inFFXOptions(typically generated).- Self-contained persistent sessions on Android, iOS, macOS, Windows,
Linux, and web — no plugins. Sessions restore at initialize with
auth.currentUserhydrated from the stored snapshot and a background reconcile;authStateChanges()is aStream<FFXUser?>whose first event is the real current state. - Built-in opt-in query cache (
FFXFetchPolicy: networkOnly/networkFirst/cacheFirst/cacheOnly) with honestFFXQueryMetadata; the fictionalisFromCache: false/hasPendingWrites/ client-clockserverTimefields are gone. FFXApiError.userMessage: human-safe copy for every failure.- Storage:
uploadreturns an awaitableFFXUploadTaskwith progress, cancellation, and in-place transfer retry;getDownloadUrlcaches and single-flights signed URLs;getFile/updateFile/deleteFilecover the file record surface;FFXImagerenders private files by id. - Database:
query()parameters optional;pages()/records()cursor-following streams;aggregate()returns a typedFFXAggregateResult;batch()is the single typed batch API. FFXSignOutScopeenum replaces the stringly-typed sign-out scope;FFXGeoPointvalue type added.- Built-in generator:
dart run flutterflow_cloud:generateemits typed models/collections/queries/options from.ffx/project.json— fast, deterministic, formatted, no build_runner.