Releases: Project516/firestore_client
Release list
v0.6.0
0.6.0
- Breaking: the central-auth-platform defines are renamed
CENTRAL_PROJECT_IDandCENTRAL_FUNCTIONS_BASE_URL(from
SPECTRUM_CENTRAL_PROJECT_ID/SPECTRUM_CENTRAL_FUNCTIONS_BASE_URL), and
centralProjectIdno longer defaults to Spectrum's own Firebase project.
This package has no built-in central project now:CentralRestAuthClient
throwsArgumentErrorat construction ifCENTRAL_PROJECT_IDis unset and
nocentralFunctionsBaseUrlwas passed explicitly, instead of silently
resolving tospectrumtasks-81c63. An app depending on the old default
passes--dart-define=CENTRAL_PROJECT_ID=<its central project>(or
centralFunctionsBaseUrldirectly) going forward. - Doc comments and the README no longer name Spectrum specifically; the
central-auth-platform handshake is a general pattern, not tied to one team.
v0.5.1
GoogleDesktopOAuth.signInnow bounds the wait for the loopback redirect
with atimeout(default 5 minutes). Closing the browser tab before
finishing the flow sent nothing to the loopback server, so the returned
future never settled and a desktop sign-in attempt hung until the app was
restarted (Spectrum3847/SpectrumStrategy#1694).
v0.5.0
The central Spectrum App Platform project is now a build-time define instead of a hard-coded constant.
centralProjectIdreadsSPECTRUM_CENTRAL_PROJECT_ID, defaulting tospectrumtasks-81c63.defaultCentralFunctionsBaseUrlreadsSPECTRUM_CENTRAL_FUNCTIONS_BASE_URL, defaulting tohttps://us-central1-$centralProjectId.cloudfunctions.net, so overriding only the project id moves the endpoint with it.
Both defaults are exactly the values 0.4.1 shipped, so a build that passes no defines is unchanged. An overridden base URL still has to be https, since it carries a bearer token.
This exists so another team can run a Spectrum app against their own central platform by setting a build flag, instead of forking this package and re-tagging it on every release.
v0.4.1
Hardening for CentralRestAuthClient and runCentralApprovalRecheck, found
reviewing an orphaned duplicate of the 0.4.0 work (#14,
closed as a dead duplicate) against what actually shipped
(#15):
- The bearer-token origin check no longer allows a loopback
http://URL.
Tests pointhttpClientat a mock instead of relaxing the runtime check,
since the token would otherwise ride in clear over any origin matching
localhost/127.0.0.1/::1. getCustomToken's request URL is now built from the base URL's parsed path
plus the callable name as a normalized path segment, instead of string
concatenation, so a trailing slash, query, or fragment on
centralFunctionsBaseUrlcan no longer misdirect the request.CentralRestAuthClient.close()no longer closes a caller-supplied
httpClient. It previously closed it viaFirebaseAuthSession.close()
regardless of who owned it.- A 200 response from the callable with an unexpected shape (no
result
key) now throwsCentralAuthExceptioninstead of an uncaughtTypeError. runCentralApprovalRecheckdistinguishes a malformed persisted session
(deleted, reported assessionRevoked) from a transient failure
(deferred), and no longer reports a recheck asdeferredafter the
callable has already succeeded andonApproved's side effects have
already run -- a failure persisting the rotated session now surfaces as a
real exception instead of being misreported as inconclusive.TimeoutHttpClientno longer follows redirects automatically, so a
same-host or subdomain redirect can no longer carry theAuthorization
bearer token to it. This also coversgetCustomToken's own request and
everyFirebaseAuthSessionrequest (sign-in, token refresh, display-name
update, provider linking) directly, since both apps that use this package
inject their ownhttpClientinstead of this package's
TimeoutHttpClient, so the fix could not rely on that wrapper alone.FirebaseAuthSession.restore(and soCentralRestAuthClient.restore) now
treats a wrong-typed persisted field (auidthat decoded to something
other than a string, for example) the same as a missing one -- returns
null instead of throwing aTypeError-- so a caller reading a malformed
local blob does not have to catch aTypeErrorto find out.
v0.4.0
Adds the central Spectrum App Platform handshake, so SpectrumStrategy and SpectrumPit share one implementation instead of each carrying a copy.
Added
CentralRestAuthClient— the REST handshake (Google ID token, central session,getCustomToken) for any platform that cannot usecloud_functions. That is Linux desktop, and mobile wherever registering a second native FlutterFire app on the central project is not wanted.CentralAuthErrorKindandclassifyCentralAuthError— one place that decides whether a failure means "not approved" or "unreachable". That distinction is the difference between a member working fine offline and being signed out, so two apps disagreeing about it is a silent lockout. Takes either spelling of the callable's status,PERMISSION_DENIEDfrom the REST error orpermission-deniedfrom a FlutterFireFirebaseFunctionsException.code, so a FlutterFire caller reuses it without this package depending oncloud_functions.runCentralApprovalRecheckandCentralRecheckOutcome— the periodic approval re-check against a persisted central session. Takes aCentralSessionStorageand plainonApproved/onDeniedcallbacks rather thanSharedPreferences, so the cadence and denial threshold stay app policy while the network call and its classification live here.CentralHandshake,CentralProfile,CentralAuthException.TimeoutHttpClient— bounds every request.FirebaseAuthSessionsets no deadline of its own, so an unbounded client meant sign-in could hang forever on a black-holed connection. It is the constructor default, so a caller cannot reintroduce that by omission.
Notes
Additive. Dependencies are unchanged, still crypto and http only, which is the point of this package: it works where FlutterFire does not.
Two fixes went in during review that are worth calling out. The default transport deadline now covers the callable's own 90 second allowance, so a cold start no longer dies in the socket and get misreported as unreachable. And the callable base URL is validated as HTTPS, since every call to it carries the central session's bearer token.
97 tests pass.
v0.3.0
Account management on FirebaseAuthSession, so a client on the REST path can do what the FlutterFire SDK already could.
updateDisplayName(name)renames the account without a re-sign-in. Fields the Identity Toolkit response omits are carried over from the current user rather than cleared.linkWithIdp/linkGoogleIdToken(googleIdToken)link a second provider credential to the signed-in account, so both credentials sign in to one uid. The account keeps its own profile: the response carries the linked provider's name and email, and adopting those would swap the signed-in identity for the one just attached to it.unlinkProvider(providerId)andlinkedProviders(), with the newLinkedProvidertype.
Also in this release: the codec is now tested against a Firestore REST document whose wire encoding was read from a live database rather than written from memory. No behavior change; see test/fixtures/README.md.
Callers that only sign in and read Firestore need no changes.
v0.2.1
- Non-finite doubles. Firestore encodes
NaN,Infinityand-Infinityas
strings in REST values; the codec now writes them in that form instead of
emitting invalid JSON, and reads them back as Dart doubles. signInawaitsexchangeCodeinside itstryblock. Same behavior, and it
clearsunawaited_return_in_try_blockunder Dart 3.13.1's analyzer.
v0.2.0
Firestore.pollCollection: cancelling the subscription now stops the polling
loop promptly, even while it is waiting between polls; the pending delay
resolves early instead of letting the loop run a final poll afterward.- Offline reads.
Firestoretakes an optionalFirestoreCache; a successful
getDocument,listDocumentsorrunQueryis cached, and a later read that
cannot reach the server is served from the cache withDocument.fromCache
set.FileFirestoreCachepersists across a relaunch,
InMemoryFirestoreCachedoes not. Without a cache the client behaves exactly
as before. - A 403 or 404 never falls back to cached data: the server answered, so stale
data would be wrong. A 429 or 5xx does fall back, as does any failure to reach
the server at all. A 404 also drops the cached copy, so a deleted document
cannot come back. Firestore.clearCache(), for sign-out.- Offline writes.
Firestoretakes an optionalFirestoreWriteQueue; a write
that cannot reach the server is queued andflushWrites()replays it. Writes
replay oldest first and the flush stops at the first still-unreachable one, so
order is preserved. A write the server refuses (403, a failedexists
precondition) is dropped and reported inFlushResult.rejectedrather than
blocking the queue behind it forever. - A queued
setDocumentorcreateDocumentreturns a localDocumentwith
fromCacheset: the caller's own value, since the server has not seen it. A
createDocumentwith no explicit id is never queued, because the id would come
from the server. - An offline
deleteDocumentdrops the cached copy immediately, so a later
offline read cannot serve a document the caller already deleted. FirebaseAuthSession.restorekeeps the session when the token endpoint cannot
be reached, instead of treating that as a revoked token and signing the user
out. A relaunch with no network resolves the persisted user;getIdToken
still fails until the network returns.FileFirestoreCache.clear()removes
only its own entries and leaves the directory in place, so a cache pointed at
a directory the host also uses cannot delete unrelated state.FileFirestoreCachehashes keys into filenames, so a long key (arunQuery
key holds the whole encoded query) stays inside the filesystem's name limit,
and each write uses its own temporary file.- A cache that throws on write never downgrades a successful read: the payload
the server returned is still returned, uncached.
v0.1.0
- Initial release:
FirebaseAuthSession(Identity Toolkit sign-in +
Secure Token refresh + session persistence),GoogleDesktopOAuth
(loopback + PKCE),Firestore(get/create/set/delete/list/runQuery +
polling change stream), andFirestoreValueCodec. Firestore.commitUpdate: masked updates throughdocuments:commitwith
atomic array transforms (appendMissingElements/removeAllFromArray, the
REST equivalents ofarrayUnion/arrayRemove) and an optional
exists: trueprecondition.FirestoreApiExceptioncarries the canonicalstatusname and an
isNotFoundhelper; batch-endpoint error arrays are parsed.