flutterflow_cloud 0.8.0-dev.2
flutterflow_cloud: ^0.8.0-dev.2 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.8.0-dev.2 #
A prerelease that brings 0.7.0's Google sign-in to the Dynamic Links line:
it carries everything in 0.7.0 and 0.8.0-dev.1. It does not yet carry
0.6.1's changes. Opt in with flutter pub add flutterflow_cloud:0.8.0-dev.2.
- Add
auth.signInWithGoogleandFFXSystemGoogleSignInBrowser, as in 0.7.0 (below). - Requires
flutterflow_cloud_emulator0.3.0-dev.2 for the local Google consent flow. - Dynamic Links is off behind a backend a preview injected (App Preview, a
shared app's release build) unless the build carries
FFX_LINK_DOMAIN.isConfiguredwas true there, andcreateLinkfailed against a data plane with no link routes; it now throwsFFXDynamicLinksNotConfiguredErrorbefore sending anything. An emulator the app was pointed at stays the link host.
0.8.0-dev.1 #
A prerelease of Dynamic Links. It builds on 0.6.0 and does not carry 0.6.1's
or 0.7.0's changes (Google sign-in among them); stay on 0.7.0 if you use
them. Opt in with flutter pub add flutterflow_cloud:0.8.0-dev.1.
- Add Dynamic Links,
cloud.dynamicLinks, in its own library:import 'package:flutterflow_cloud/dynamic_links.dart';. It makes links to a route (createLink,createLinkToLocation), resolves them (resolve), and turns a URL the app receives into the route it opens (open, a sealedFFXLinkOpen;locationOffor a router's link resolver), reporting opens and failed resolutions to the link host. It is off, and sends nothing, unless the build carries--dart-define=FFX_LINK_DOMAIN=…(andFFX_LINK_SCHEME=…) or the instance talks to an emulator; making or resolving a link then throwsFFXDynamicLinksNotConfiguredError. An app with adynamicLinkmodel keeps its generateddynamicLinksgetter; a file that imports this library too names the extension:FFXCloudDynamicLinks(cloud).dynamicLinks. - The
dynamicLinks*problem codes map to typed errors with end-user copy.
0.7.0 #
- Add
auth.signInWithGooglewith PKCE, state validation, cancellation and persistent FlutterFlow Cloud sessions. Firebase Auth is not required. - Add
FFXSystemGoogleSignInBrowserfor web popups and native system browsers, exported byflutterflow_cloud.dartandgoogle_sign_in.dart. Register the app's exact callback URL and complete Google setup through its connection. - Support the local Google consent flow in
flutterflow_cloud_emulator0.2.0. - Upgrade existing apps with
flutter pub add flutterflow_cloud:^0.7.0, then regenerate bindings withdart run flutterflow_cloud:generate. Version 0.6.0 does not expose Google sign-in.
0.6.0 #
-
Add callable Functions through
cloud.functions.calland generated typed methods inlib/ffx/functions.g.dart. Regenerate existing app bindings withdart run flutterflow_cloud:generateafter upgrading. -
Share pure Dart values, strict Functions codecs and project generation through the published
flutterflow_cloud_corepackage. -
Breaking: a function call is sent once and never again. The platform keeps no idempotency record for function calls, so a second request could run the function twice.
app.functions.calland the generated typed methods send noIdempotency-Key, ignoreFFXRetryPolicy, and surface every failure after one request: a lost connection, a broken or malformed body, a 5xx,functionsUnavailable,quotaExceededand aRetry-Afterincluded. Before, the SDK resent the call under one key and the platform replayed the stored answer. A definite pre-admissiontokenExpiredstill renews the token and sends once more, because nothing started.FFXFunctionCallOptions.idempotencyKey,FFXFunctionCallMetadata'sidempotencyKeyandstored, and theidempotencyKeyofFFXFunctionTransportError,FFXFunctionCancelledErrorandFFXFunctionDeadlineErrorare gone. A call that must be safe to retry sends its own request ID indata, and the function ignores an ID it has already handled.FFXFunctionErrorgainsretryAfterMs, the delay aRetry-Afternamed (afunctionsUnavailablerefusal sends one), so the app can decide whether to call again. Database, auth and connector mutations keep theirIdempotency-Keyand retries.
0.5.0 #
Everything since 0.4.1, with store purchases out of pre-release.
- Store purchases:
cloud.purchases(package:flutterflow_cloud/purchases.dart) reads what the app sells and what the signed-in user bought, checks App Store and Google Play purchases (withrestored: truefor Restore purchases), records the payments kit's events and carries the credits balance, as listed under 0.4.0-dev.1, 0.5.0-dev.1 and 0.5.0-dev.2.FFXInsufficientCreditsErroris the refusal of a write whose rule spends more credits than the end user has.FlutterFlowCloud.insidePreviewis public. - Add
cloud.usesEmulator: whether the instance talks to App Preview's backend or a local emulator, where only drip's pretend store can buy.FlutterFlowCloud.insidePreviewstays true only inside App Preview. - Add atomic numeric increments:
FFXFieldValue.increment(delta)in collectionupdateand batch-update patches ({'count': FFXFieldValue.increment(1)}), and a typedincrement(id, …)on generated collections for writable top-level numeric fields. A missing or null value starts at zero. - Add
auth.setCustomClaimfor per-claim app delegation, including null revocation, revision preconditions and caller idempotency keys. - A preview whose backend is still waking, or keeps refusing, is asked again less often, and the auth event stream backs off to 30 s, as listed under 0.5.0-dev.2.
0.5.0-dev.2 #
A pre-release for trying store purchases before they launch. cloud.purchases
may still change before 0.5.0.
cloud.purchases.checkAppStoreandcheckGooglePlaytakerestored: truefor a purchase the store gave back on Restore purchases. drip then moves an upgrade or unlock another account of the app holds to the signed-in one (a guest who bought on one phone gets it back on another); a pack's credits stay with the account that bought them. Without it, such a purchase is still refused withpurchaseHeldByAnother.- A published preview whose thread is still waking is asked again less often
each time: after the server's
Retry-After, then half as long again, at most every 30 s, inside the five-minute start-up allowance. Before, every request asked again every five seconds, and a preview whose thread never woke kept doing so for as long as its tab stayed open. - The auth event stream's reconnect delay keeps doubling to 30 s when the
server sends a short
Retry-After; before, the hint replaced the backoff, so a waking backend'sRetry-After: 5held it at five seconds. - The auth event stream no longer asks again after a refusal the backend repeats (a 4xx the retry engine never retries, such as an expired App Preview ticket or a stopped thread). It waits until the session or the base URL changes; an App Preview host renews its ticket in the base URL.
0.5.0-dev.1 #
A pre-release for trying store purchases before they launch: 0.4.0 with
cloud.purchases and the public FlutterFlowCloud.insidePreview, as listed
under 0.4.0-dev.1 (0.4.0 shipped without them). cloud.purchases may still
change before 0.5.0.
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.
0.4.0-dev.1 #
A pre-release for trying store purchases before they launch; cloud.purchases
may still change before 0.4.0.
cloud.purchases.recordEvents(events)posts what the app's paywall and shop saw (FFXPurchaseEvent: id,FFXPurchaseEventKind, at, source, item, plan, amount) to/v1/purchases/eventsfor Payments' Reports, and answers how many were new.FFXInsufficientCreditsError(anFFXConflictError, codeinsufficientCredits): a write whose rule callsspend()needs more credits than the end user has. It carriescredits,neededandbalance, anduserMessagecopy for the end user.FFXPurchaseState.credits(FFXCredits): the app's credits as the backend keeps them,balance(bought plus this month's free),bought,free,freeEachMonthandfreeRefillsAt, withwords(n)for "3 vet questions". A pack is checked like any purchase;checkPretendtakes itsamount.- Store purchase problems from
/v1/purchases(purchaseNotVerified,purchaseNotSold:FFXValidationError;paymentsNotConfigured,purchaseHeldByAnother:FFXConflictError) carryuserMessagecopy for the buyer. cloud.purchasesreads what the app sells and what the signed-in user bought (read()→FFXPurchaseState: purchase id, upgrade, owned unlocks, purchases and products with each store's ids) and checks a store purchase (checkAppStore,checkGooglePlay; in the preview,checkPretendrecords a purchase on drip's pretend store as anFFXStore.pretendtest purchase, in the preview's backend only), refreshing the session when the upgrade changes.FlutterFlowCloud.insidePreviewis public.cloud.purchasesis an extension (FFXCloudPurchases) inpackage:flutterflow_cloud/purchases.dart, with the purchase types; the main library doesn't export it, so an app's ownpurchasesgetter (apurchasemodel's) is untouched.- 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.