stream_core 0.5.0
stream_core: ^0.5.0 copied to clipboard
Internal sdk with low-level utilities for the stream SDKs
0.5.0 #
💥 BREAKING CHANGES #
- Raised the minimum Dart SDK to
^3.12.0 - Removed the
userIdparameter fromUserToken.anonymous, anonymous tokens always useUser.anonymousUserId - Removed the
TokenManager.tokenProvidersetter, usesetTokenProviderinstead TokenManager.userIdis now nullable, and isnulluntil an identity is configuredUsernow requires a user of typeUserType.anonymousto carryUser.anonymousUserIdas its id. A mismatch fails to compile in a const context, and throws in debug mode otherwiseStreamWebSocketClientnow takes anoptionsBuilderinstead ofoptions, called once per connection attemptWebSocketOptions.connectTimeoutis now a non-nullableDuration, 30 seconds by default, and is honoured: a connection that does not come up is given up on instead of waited on indefinitely. A connection that drops later is retried for you; aconnectthat times out is not, so call it again- Renamed
StreamWebSocketClient.onConnectionEstablishedtoonAuthenticate, now aWebSocketAuthenticator. It is handed aWsRequestSenderand theStreamApiExceptionthe server closed the previous attempt with, and throws to say the credentials did not go out - Reworked the error layer around one sealed root: every failure the SDK reports is a
StreamExceptionof four kinds —StreamApiException,StreamNetworkException,StreamAuthenticationExceptionorStreamClientException StreamExceptionno longer takes or carries astackTrace. A trace records where a failure was raised rather than what it was, so it travels beside the failure: onFailure, or onServerInitiatedandAuthenticationFailedfor a connection that closed. Where the exception is built at the throw site,throwcaptures it- Removed
ClientException,HttpClientExceptionandWebSocketEngineException, replaced by the kinds above.StreamDioException.exceptionis aStreamException, and theStreamDioExceptionExtensionextension is nowDioExceptionMapping, withtoClientException()renamed totoStreamException() StreamWebSocketClient.sendnow fails with aStreamExceptionrather than passing the engine's own error through, so aFailurethat carried aStateErroror a codec error now carries aStreamNetworkExceptionorStreamClientException. TheWsRequestSenderhanded to aWebSocketAuthenticatorchanged the same way, which matters where its error is propagated intoAuthenticationFailedStreamWebSocketClient.sendthrows aStateErrorwhen nothing has connected yet, rather than reporting it through the returnedResultStreamDioExceptionno longer defaults itsstackTracetoStackTrace.current, leaving Dio to substitute the stack captured where the request was madeServerInitiated.erroris typedStreamException?rather thanWebSocketEngineException?TokenManager.getTokenfails with aStreamAuthenticationExceptionrather than raw errors; a failed provider's own error is preserved ascause. A provider failure that is already aStreamException, or aTimeoutException, keeps its own kind, so a load that failed at the moment stays retriable- Replaced
StreamApiError.isTokenExpiredError,isClientErrorandisRateLimitError: the conditions live onStreamErrorCodeandStreamApiExceptionasisTokenExpired,isTokenNotYetValid,isTokenSignatureInvalid,isApiKeyInvalidandisRateLimited;StreamApiErrorkeeps onlyisRateLimited StreamApiError.codeis typedStreamErrorCoderather thanint; construction takesStreamErrorCode(40)in place of40, reads are unchangedAuthInterceptorextendsInterceptorrather thanQueuedInterceptor, so requests are no longer serialised against one anotherWebSocketConnectionState.isAutomaticReconnectionEnabledreads the error's facts: token conditions that heal, rate limits and transient network failures reconnect; refused signatures or API keys, other 4xx andunrecoverableverdicts do notResult.getOrElse,getOrDefault,recoverandrecoverCatchingreturn the result's own type and no longer take a type parameter. To widen, widen the result (Result<num> widened = intResult) or usefold- Replaced the logger:
StreamLoggeris the handle you write with and aStreamLogHandleris where records go, soPriority,MessageBuilder,Tag,IsLoggableValidatorandFinderare renamed or gone LoggingInterceptorwrites through the logger rather than printing, so it is silent until an app asks for records. ItslogPrintis now optional, and it takes atag- Reworked attachment uploads around
AttachmentUploadTask:StreamAttachmentUploader.uploadreturns the running task rather than aFuture, anduploadBatchreturns anAttachmentUploadBatch.CancelTokenand progress callbacks are gone from the public API - Removed
StreamAttachment.uploadState. Where an upload has got to lives on the task running it, not on the attachment - Replaced the
UploadState*classes withUploadQueued,UploadPreparing,UploadInProgress,UploadSuccess,UploadFailedandUploadCancelled, constructed directly rather than through named constructors.UploadInProgress.progressis anUploadProgressin bytes rather than adouble, andUploadFailed.erroris aStreamException - Removed
AttachmentUploadException. A failed upload carries theStreamExceptionthat stopped it, and a cancelled one aStreamNetworkExceptionwithisCancelledset - Removed the
OnUploadProgressandOnBatchUploadProgresscallbacks along with theStreamAttachmentUploaderBatchextension. Progress arrives onAttachmentUploadTask.stateandAttachmentUploadBatch.state, so it can never disagree with the lifecycle uploadBatch'smaxConcurrentnow defaults to3rather than5UploadedAttachmentcompares by value rather than by identity
✨ Features #
- Added a logger the SDK now reports itself through, silent until an app names both a destination and a priority on
StreamLogger, or hands a product client aStreamLogConfigcarrying both - Added
TokenManager.setTokenProvider, which points an existing manager at another user and expires the cached token; handed the identity it already has, it does nothing - Added optional
onTokenUpdatedcallback toTokenManager, invoked after every successful token load - Added optional
rawValuetoUserToken.anonymous, so an anonymous token can carry a JWT granting restricted access; itsuser_idclaim must be!anon - Added
UserToken.expiresAt, from the token'sexpclaim, andUserToken.isExpired, which takes an optionalleeway - Added
User.anonymousUserId, the id every anonymous user has User.guesttakes animage, which it previously dropped- Added
TokenManager.unconfigured, for a client that exists before its user does, andTokenManager.reset, which drops the configured identity and its cached token - Added
teamsfield toUserclass - Added
StreamDateTimeConverter, aJsonConverterfor the API'sDateTimefields. Accepts either an RFC3339 string (v1) or epoch nanoseconds (v2) when deserializing, and always serializes to RFC3339. Values are normalized to UTC with microsecond precision - Added
DioException.toStreamException(), mapping a Dio failure to theStreamExceptionit represents - Added
StreamApiException.retryAfter, the wait the server asked for, read from theRetry-Afterheader on any error response carrying one — a 503 populates it as readily as a 429. Only the delta-seconds form is read - Added
StreamErrorCode, the API's error-code registry as named constants overint, tolerant of codes the SDK does not know yet - Added
runApiSafely, which runs an API call and reports every failure as aStreamException - Added
DisconnectionSource.connectTimeoutandauthenticationFailed, andisReconnectable, whether a connection closed for that reason is worth opening again - Added
DisconnectionSource.cause, the error that closed the connection, ornullwhen the source carries none - Added
stackTracetoServerInitiatedandAuthenticationFailed, where the failure was raised;nullfor a closure the server reported, which arrives as data rather than as something raised - Added
ConnectUserDetailsRequest.fromUser, which builds the details a client may send from aUser - Added
StreamWebSocketClient.dispose, which closes the connection along witheventsandconnectionState; the client is nowDisposable, andconnectthrows aStateErrorafterwards - Added
InFlightCache, which hands concurrent callers asking for the same key the one call already in flight, and its outcome, success or failure alike - Added
AttachmentUploadTask, one upload as an object:statecarries the whole lifecycle including byte progress,resultsettles once and never throws, andcancelcalls it off at once - Added
AttachmentUploadBatch, which uploads several attachments under a concurrency limit, aggregates byte-weighted progress, and finishes as a sealedBatchUploadResult—BatchUploadCompleted,BatchUploadStoppedOnErrororBatchUploadCancelled— carrying one outcome per attachment in input order
🐛 Bug Fixes #
- Fixed
StreamApiErrorfailing to decode whendetailsis not a list of numbers, as a moderation rejection's is; such values read as empty - Fixed an error payload without a
durationormore_infofailing to decode, which lost thecodewith it and silently stopped the token refresh a code would have triggered. Both read as empty now - Fixed three faults in
TokenManager's token cache:getTokencontacted the provider on every call instead of returning the cached token, handed out a token that had already expired rather than replacing it, and cached one that finished loading afterexpireTokenorsetTokenProviderhad invalidated it. A static provider is left alone, having nothing fresher to give - Fixed
DynamicTokenProvideraccepting a token issued for a different user than the one requested - Fixed several faults in the token-expired retry: it was skipped when the response carried no JSON content type, never completed at all when the replacement was refused too, re-sent a multipart body whose streams the refused attempt had consumed, and expired a token another request had already replaced
StreamWebSocketClientno longer prints to the console- Fixed a connection that could be left open, or left disconnecting for good:
connectleaked the socket of a failed handshake,disconnectcompleted before the socket had closed, and a close that failed or found no socket reported no closure at all - Fixed reconnection eligibility: the deliberate-close and client-error checks never matched, and a rate limit was treated as permanent when it clears on its own
- Fixed
ConnectionRecoveryHandlerretrying a first connection attempt, which reconnected behind the caller ofconnect; only established connections are recovered now - Fixed a health check arriving while disconnecting reporting the connection as established again, turning a deliberate disconnect into a reconnect
🔄 Changed #
ConnectUserDetailsRequestleaves its unset fields out of the JSON it serialises, rather than sending them as nulls- Anonymous requests now always send
user_id=!anon, rather than whatever id theTokenManagerwas configured with DynamicTokenProviderchecks the token type before its user id, so a token of the wrong type is reported as such instead of as a mismatched userTokenManager.getTokenfails whenresetruns while the token is loading, and rejects a token whoseuser_idis not the user it was loading for; asetTokenProviderduring a load still serves the caller that started itAuthInterceptorno longer refreshes a token when the manager has no identity, so the original error is surfaced, and no longer retries a request signed for a user it has since been pointed away from, which would have performed one user's request as anotherStreamWebSocketEngine.openfails when a connection is already open, rather than closing it to make roomSystemEnvironmentManager.updateEnvironmentnow sanitizes the passedSystemEnvironment, so an integrator can enrich the Stream client header without changing the SDK identity it reports
0.4.0 #
💥 BREAKING CHANGES #
SharedEmitterandStateEmitternow implementStream<T>directly instead of exposing astreamgetter- Removed
streamgetter fromSharedEmitterandStateEmitter
✨ Features #
- Added
hasListenerandisClosedproperties toSharedEmitter - Added
asSharedEmitter()andasStateEmitter()extension methods for read-only views - Added
update,getAndUpdate,updateAndGetextension methods onMutableStateEmitter - Added
StreamEventbase interface andEventResolverfor event transformation
0.3.3 #
✨ Features #
- Added
partitionmethod for splitting lists into two based on a filter condition - Added
compareparameter toupdateWherefor optional sorting after updates
0.3.2 #
✨ Features #
- Added location-based filtering support with
LocationCoordinate,Distance,CircularRegion, andBoundingBox - Added
insertAtparameter toupsertfor controlling insertion position of new elements
0.3.1 #
✨ Features #
- Added
updateWheremethod for updating elements matching a filter condition - Added
batchReplacemethod for replacing multiple elements based on matching keys - Added
insertUniquemethod for inserting elements ensuring uniqueness by key with optional sorting - Added
updateparameter toupsertfor custom merge logic when replacing existing elements - Added
updateparameter tobatchReplacefor custom merge logic - Added
updateparameter tosortedUpsertfor custom merge logic when replacing existing elements
🐛 Bug Fixes #
- Fixed
StreamDioException.toClientException()not handling invalid JSON strings gracefully
0.3.0 #
💥 BREAKING CHANGES #
FilterFieldnow requires a value getter functionObject? Function(T)- Filter classes renamed (e.g.,
EqualOperator→Equal,AndOperator→And) Filtersignature changed toFilter<T extends Object>
✨ Features #
- Added
matches(T other)method for client-side filtering with PostgreSQL-like semantics - Added utility functions for deep equality, subset containment, and type-safe comparisons
- Enhanced
Sortcomparator to handle incompatible types safely
0.2.0 #
💥 BREAKING CHANGES #
- Renamed
AppLifecycleStateProvidertoLifecycleStateProviderandAppLifecycleStatetoLifecycleState
✨ Features #
- Added
keepConnectionAliveInBackgroundoption toConnectionRecoveryHandler - Added
unknownstate toNetworkStateandLifecycleStateenums
🐛 Bug Fixes #
- Fixed
onClose()not being called when disconnecting during connecting state - Fixed unnecessary reconnection attempts when network is offline
- Fixed existing connections not being closed before opening new ones
0.1.0 #
- Initial release