NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev · #1715 most downloaded on pub.dev
Internal sdk with low-level utilities for the stream SDKs
Last release 8 days ago
30 Sep 2026
Ships unpredictably
gaps range from 2 weeks to 8 months
Nearly every release is documented
notes for 9 of 9 stable releases
Nothing withdrawn
no release was ever pulled
1 years old
9 releases · first in 2025
One column per month.
Added a fix_data.yaml , so deprecated members can be migrated with dart fix --apply .
StreamColorScheme.backgroundOverlayDarkStrong, the design system's background/core/overlay-dark-strong token. A heavier version of backgroundOverlayDark, for content that has to stay legible on top of arbitrary imagery or video.StreamReactions.onReactionLongPressed, reporting the long-pressed StreamReactionsItem — or null for the cluster/overflow chip. When null, the chips register no long-press gesture, leaving it to an ancestor.StreamSplitButton, in the two variants the design covers —StreamSplitButtonVariant.regular and .destructive. Each variant carriesStreamSplitButtonStyle on StreamSplitButtonThemeData, so the twoblurFill, boltFill,cameraFlipFill, captionFill, caretDown, caretUp, copyFill,darkMode, emojiAddFill, fullBlurFill, fullscreenFill, gridFill,gridPixelFill, language, leftToRight, lightMode, menu,messageBubblesFill, moreHorizontal, moreVerticalFill, noSignFill,phoneDownFill, pinFill, pipFill, presentDesktopFill,presentMobileFill, questionCircleFill, raiseHandFill,recordLibraryFill, recordingFill, recordingStopFill, settings,settingsFill, slidersFill, starFill, statsFill, unpinFill,userAddFill, userRemoveFill, usersFill, verifiedFill, videoOffFill,voiceOffFill, and xmarkSmall.gridDefaultFill,livestreamFill, phoneFill, speakerBottomFill, speakerLeftFill,speakerRightFill, and speakerTopFill.fix_data.yaml, so deprecated members can be migrated withdart fix --apply.>=3.44.0 and the Dart SDK to ^3.12.0.StreamIcons.more / StreamIconData.more in favour ofmoreHorizontal, which keeps the original artwork. A vertical variant is nowmoreVerticalFill. Run dart fix --apply to migrate.Published to pub.dev: https://pub.dev/packages/stream_core_flutter/versions/0.5.1
CurrentPlatform.debugCurrentPlatformOverride, which points CurrentPlatform at a chosen PlatformType in testsFilter.raw, a last resort for a query this package does not model. It serializes verbatim, is not validated, and cannot be evaluated locally, so matches throws for itFilterField.collectionEquality, which declares whether Filter.equal asks a collection field to hold every given element, or to hold nothing else eithernormalizeStringForSort, which folds diacritics, ligatures and case so a locally sorted list of names matches the order a query returnssortedUpsertAt, which upserts at an index the caller already has instead of searching for onesortedMerge, an O(n + m) merge for a receiver that is already sorted, which skips sorting other when it already arrives in order. Unlike merge it never re-sorts the whole result, so it stays flat as the receiver growssortedWith, a stable sort: elements the comparator calls equal keep the order they arrived in, where sorted reorders them once the list is longer than 32merge now accepts a nullable other, so a list straight off a response needs no null checkStreamWebSocketClient.optionsProvider, which builds the options asynchronously and is given the error that closed the previous attempt, within defaultOptionsTimeoutConnectionStateEmitter.settled, which completes once the connection is no longer in transitioncloseReason, cause and isReconnectable moved onto the DisconnectionSourceReads extension, which adds exception and stackTrace. cause is now StreamException?StreamWebSocketClient.optionsBuilder and WebSocketOptionsBuilder, in favour of optionsProvider and WebSocketOptionsProvider. A builder takes no arguments, so it cannot be told what closed the last attemptSystemInitiated, carrying the error, rather than ServerInitiated; both reconnectconnect awaiting a provider that never answersStreamLogHandler.console now prefixes every line of a message that spans severalFilter.equal and Filter.in_ now ask whether a collection field holds the values given, rather than comparing it with order-sensitive deep equality that no query can produceLocationCoordinate equality is now exact, where == matched within ~1.1cm and so disagreed with hashCode, Set and Map. distanceTo no longer reports 0m for points closer than that; for proximity, ask a.distanceTo(b) <= 1.meterssortedUpsert now leaves a replacement in place when it sorts to the same position, instead of moving it after the elements it ties withupdateWhere now returns the receiver when nothing matches, so an unchanged list keeps its identitysortedInsert, sortedUpsert, sortedUpsertAt and sortedMerge now assert in debug that the receiver is sorted by compare. Breaking that never threw, it quietly misplaced elementsupdateWhere and sortedMerge sorted through sorted, which reorders elements the comparator calls equal once a list is longer than 32. Both are stable nowPublished to pub.dev: https://pub.dev/packages/stream_core/versions/0.5.1
Deprecated StreamReactions.onPressed in favor of onReactionPressed .
StreamReactions.onReactionPressed, which reports the pressed StreamReactionsItem — or null for the cluster/overflow chip, which represents no single reaction. Added an optional StreamReactionsItem.key so callers can identify the pressed item.semanticsLabel to StreamAvatar, StreamAvatarGroup, and StreamAvatarStack. On StreamAvatar, null (default) drops the placeholder's initials from the semantics tree via ExcludeSemantics; a non-null value exposes it as a labeled image node. On StreamAvatarGroup / StreamAvatarStack, null composes through — each child's own semanticsLabel applies — while a non-null value collapses the group into a single labeled image node and hides children and the "+N" overflow badge.StreamColorScheme.fromSeed — builds a complete light or dark color scheme from a single brand color, optionally with a custom chrome color. When chrome is omitted it is derived from the brand hue at StreamColorScheme.neutralChroma.StreamColorSwatch.fromColor now generates shades in the HCT color space instead of HSL. Each shade takes its tone from a fixed ladder measured from the Stream design tokens, so a shade's contrast is predictable regardless of the seed's hue — seeding a light color such as yellow now yields an accent that can carry white text. Two consequences: the seed is no longer reproduced verbatim at shade 500 (it is normalized onto the ladder), and dark scales now mirror the ladder so the seed's tone lands on shade 300, matching the default dark palette.StreamScaffold — a full-page scaffold for regular or floating bars; a floating bar enlarges the body's MediaQuery.padding so scrollables inset themselves.StreamBottomNavBar and StreamBottomNavBarItem — a bottom navigation bar rendering as a docked bar or a floating pill, themeable via StreamBottomNavBarTheme. Its height is kStreamBottomNavBarHeight.StreamSafeArea — a SafeArea that insets by max(systemInset, minimum) + margin, so a pinned surface keeps a gap from the system bars. StreamSafeArea.driven animates the inset; resolveInsets returns it as a value.StreamAppBar and StreamBottomAppBar via StreamAppBarStyle.surfaceStyle / StreamBottomAppBarStyle.surfaceStyle, plus StreamBottomAppBarStyle.floatingBackgroundColor for the upward fade.StreamToolbarScope for its slots, and reports it through a resolveSurfaceStyle static so a container can match its layout.StreamToolbarButton — a toolbar action, labelled or icon-only, that takes its look from the enclosing StreamToolbarScope; pass type to override the resolved shape.StreamMediaViewer chrome now follows the ambient StreamSurfaceStyle — floating over full-bleed media, or docked with the media inset between the bars.isFloating to StreamAvatar, StreamAvatarGroup, and StreamAvatarStack, rendering a Material elevation (StreamAvatarThemeData.floatingElevation) instead of a hand-painted shadow.streamFloatingFade helper — a shared LinearGradient factory (alpha stops 0xE8/0xA8/0x40/0x00 with solid-fraction support for safe-area zones) used internally by StreamAppBar, StreamBottomNavBar, and StreamMessageComposer floating fade effects.isFloating to the default StreamButton constructor — the floating (elevated) appearance was previously reachable only through StreamButton.icon. Labelled buttons now get the same treatment: elevation for every type, plus a backgroundElevation1 fill for outline and ghost.StreamElevation — the four elevation levels of the design system as logical pixels, for passing to Material.elevation or a component theme's elevation field. Like StreamRadius and StreamSpacing it is a theme primitive: reachable as StreamTheme.elevation or context.streamElevation, overridable per theme through the StreamTheme constructor, and lerped on theme transitions. StreamElevation.none is a fixed 0 rather than a themeable level, so "flat" cannot be redefined as elevated. StreamAvatar and StreamButton now resolve their elevations from it instead of hard-coded numbers; the rendered values are unchanged.chipStyle to StreamReactionsThemeData for overriding the per-reaction chip appearance (background, size, etc.); it is merged over the default reaction chip style.StreamMessagePresentation and StreamMessageLayoutData.presentation, describing whether a message is drawn inline in the list (standard) or as a preview above a scrim (preview, e.g. the long-press message-actions modal). Read it with StreamMessageLayout.presentationOf(context), or resolve per-presentation styling through StreamMessageLayoutProperty.resolveWith. For preview, the default metadata (username, timestamp, edited, status), annotation (text, icon, trailing) and replies-label colors now resolve to StreamColorScheme.textOnAccent so they stay legible against StreamColorScheme.backgroundScrim. Also added StreamMessageLayoutData.copyWith.StreamNetworkImage now caches through a shared cache manager which, on IO platforms, is stored in its own app-scoped directory (isolated from the host app's image cache) with LRU eviction, while other platforms fall back to the library defaults.isFloating: true) now retain their pill surface (backgroundElevation1) when disabled, across all style/type combinations. Previously, outline and ghost variants fell back to transparent when disabled, losing the floating visual.StreamReactions.onPressed in favor of onReactionPressed.StreamTheme.brightness. Read colorScheme.brightness instead. The property, and the brightness parameter on copyWith and StreamTheme.raw, all keep working — for a theme built through the StreamTheme factory the value still mirrors colorScheme.brightness.Published to pub.dev: https://pub.dev/packages/stream_core_flutter/versions/0.5.0
^3.12.0userId parameter from UserToken.anonymous, anonymous tokens always use User.anonymousUserIdTokenManager.tokenProvider setter, use setTokenProvider insteadTokenManager.userId is now nullable, and is null until an identity is configuredUser now requires a user of type UserType.anonymous to carry User.anonymousUserId as its id. A mismatch fails to compile in a const context, and throws in debug mode otherwiseStreamWebSocketClient now takes an optionsBuilder instead of options, called once per connection attemptWebSocketOptions.connectTimeout is now a non-nullable Duration, 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; a connect that times out is not, so call it againStreamWebSocketClient.onConnectionEstablished to onAuthenticate, now a WebSocketAuthenticator. It is handed a WsRequestSender and the StreamApiException the server closed the previous attempt with, and throws to say the credentials did not go outStreamException of four kinds — StreamApiException, StreamNetworkException, StreamAuthenticationException or StreamClientExceptionStreamException no longer takes or carries a stackTrace. A trace records where a failure was raised rather than what it was, so it travels beside the failure: on Failure, or on ServerInitiated and AuthenticationFailed for a connection that closed. Where the exception is built at the throw site, throw captures itClientException, HttpClientException and WebSocketEngineException, replaced by the kinds above. StreamDioException.exception is a StreamException, and the StreamDioExceptionExtension extension is now DioExceptionMapping, with toClientException() renamed to toStreamException()StreamWebSocketClient.send now fails with a StreamException rather than passing the engine's own error through, so a Failure that carried a StateError or a codec error now carries a StreamNetworkException or StreamClientException. The WsRequestSender handed to a WebSocketAuthenticator changed the same way, which matters where its error is propagated into AuthenticationFailedStreamWebSocketClient.send throws a StateError when nothing has connected yet, rather than reporting it through the returned ResultStreamDioException no longer defaults its stackTrace to StackTrace.current, leaving Dio to substitute the stack captured where the request was madeServerInitiated.error is typed StreamException? rather than WebSocketEngineException?TokenManager.getToken fails with a StreamAuthenticationException rather than raw errors; a failed provider's own error is preserved as cause. A provider failure that is already a StreamException, or a TimeoutException, keeps its own kind, so a load that failed at the moment stays retriableStreamApiError.isTokenExpiredError, isClientError and isRateLimitError: the conditions live on StreamErrorCode and StreamApiException as isTokenExpired, isTokenNotYetValid, isTokenSignatureInvalid, isApiKeyInvalid and isRateLimited; StreamApiError keeps only isRateLimitedStreamApiError.code is typed StreamErrorCode rather than int; construction takes StreamErrorCode(40) in place of 40, reads are unchangedAuthInterceptor extends Interceptor rather than QueuedInterceptor, so requests are no longer serialised against one anotherWebSocketConnectionState.isAutomaticReconnectionEnabled reads the error's facts: token conditions that heal, rate limits and transient network failures reconnect; refused signatures or API keys, other 4xx and unrecoverable verdicts do notResult.getOrElse, getOrDefault, recover and recoverCatching return the result's own type and no longer take a type parameter. To widen, widen the result (Result<num> widened = intResult) or use foldStreamLogger is the handle you write with and a StreamLogHandler is where records go, so Priority, MessageBuilder, Tag, IsLoggableValidator and Finder are renamed or goneLoggingInterceptor writes through the logger rather than printing, so it is silent until an app asks for records. Its logPrint is now optional, and it takes a tagAttachmentUploadTask: StreamAttachmentUploader.upload returns the running task rather than a Future, and uploadBatch returns an AttachmentUploadBatch. CancelToken and progress callbacks are gone from the public APIStreamAttachment.uploadState. Where an upload has got to lives on the task running it, not on the attachmentUploadState* classes with UploadQueued, UploadPreparing, UploadInProgress, UploadSuccess, UploadFailed and UploadCancelled, constructed directly rather than through named constructors. UploadInProgress.progress is an UploadProgress in bytes rather than a double, and UploadFailed.error is a StreamExceptionAttachmentUploadException. A failed upload carries the StreamException that stopped it, and a cancelled one a StreamNetworkException with isCancelled setOnUploadProgress and OnBatchUploadProgress callbacks along with the StreamAttachmentUploaderBatch extension. Progress arrives on AttachmentUploadTask.state and AttachmentUploadBatch.state, so it can never disagree with the lifecycleuploadBatch's maxConcurrent now defaults to 3 rather than 5UploadedAttachment compares by value rather than by identityStreamLogger, or hands a product client a StreamLogConfig carrying bothTokenManager.setTokenProvider, which points an existing manager at another user and expires the cached token; handed the identity it already has, it does nothingonTokenUpdated callback to TokenManager, invoked after every successful token loadrawValue to UserToken.anonymous, so an anonymous token can carry a JWT granting restricted access; its user_id claim must be !anonUserToken.expiresAt, from the token's exp claim, and UserToken.isExpired, which takes an optional leewayUser.anonymousUserId, the id every anonymous user hasUser.guest takes an image, which it previously droppedTokenManager.unconfigured, for a client that exists before its user does, and TokenManager.reset, which drops the configured identity and its cached tokenteams field to User classStreamDateTimeConverter, a JsonConverter for the API's DateTime fields. Accepts either an RFC3339 string (v1) or epoch nanoseconds (v2) when deserializing, and always serializes to RFC3339. Values are normalized to UTC with microsecond precisionDioException.toStreamException(), mapping a Dio failure to the StreamException it representsStreamApiException.retryAfter, the wait the server asked for, read from the Retry-After header on any error response carrying one — a 503 populates it as readily as a 429. Only the delta-seconds form is readStreamErrorCode, the API's error-code registry as named constants over int, tolerant of codes the SDK does not know yetrunApiSafely, which runs an API call and reports every failure as a StreamExceptionDisconnectionSource.connectTimeout and authenticationFailed, and isReconnectable, whether a connection closed for that reason is worth opening againDisconnectionSource.cause, the error that closed the connection, or null when the source carries nonestackTrace to ServerInitiated and AuthenticationFailed, where the failure was raised; null for a closure the server reported, which arrives as data rather than as something raisedConnectUserDetailsRequest.fromUser, which builds the details a client may send from a UserStreamWebSocketClient.dispose, which closes the connection along with events and connectionState; the client is now Disposable, and connect throws a StateError afterwardsInFlightCache, which hands concurrent callers asking for the same key the one call already in flight, and its outcome, success or failure alikeAttachmentUploadTask, one upload as an object: state carries the whole lifecycle including byte progress, result settles once and never throws, and cancel calls it off at onceAttachmentUploadBatch, which uploads several attachments under a concurrency limit, aggregates byte-weighted progress, and finishes as a sealed BatchUploadResult — BatchUploadCompleted, BatchUploadStoppedOnError or BatchUploadCancelled — carrying one outcome per attachment in input orderStreamApiError failing to decode when details is not a list of numbers, as a moderation rejection's is; such values read as emptyduration or more_info failing to decode, which lost the code with it and silently stopped the token refresh a code would have triggered. Both read as empty nowTokenManager's token cache: getToken contacted 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 after expireToken or setTokenProvider had invalidated it. A static provider is left alone, having nothing fresher to giveDynamicTokenProvider accepting a token issued for a different user than the one requestedStreamWebSocketClient no longer prints to the consoleconnect leaked the socket of a failed handshake, disconnect completed before the socket had closed, and a close that failed or found no socket reported no closure at allConnectionRecoveryHandler retrying a first connection attempt, which reconnected behind the caller of connect; only established connections are recovered nowConnectUserDetailsRequest leaves its unset fields out of the JSON it serialises, rather than sending them as nullsuser_id=!anon, rather than whatever id the TokenManager was configured withDynamicTokenProvider checks the token type before its user id, so a token of the wrong type is reported as such instead of as a mismatched userTokenManager.getToken fails when reset runs while the token is loading, and rejects a token whose user_id is not the user it was loading for; a setTokenProvider during a load still serves the caller that started itAuthInterceptor no 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.open fails when a connection is already open, rather than closing it to make roomSystemEnvironmentManager.updateEnvironment now sanitizes the passed SystemEnvironment, so an integrator can enrich the Stream client header without changing the SDK identity it reportsPublished to pub.dev: https://pub.dev/packages/stream_core/versions/0.5.0
refactor(llc)!: update Emitter architecture and implement Stream directly by @xsahil03x in #26
Full Changelog: v0.3.3...v0.4.0
SharedEmitter and StateEmitter now implement Stream<T> directly instead of exposing a stream getterstream getter from SharedEmitter and StateEmitterhasListener and isClosed properties to SharedEmitterasSharedEmitter() and asStateEmitter() extension methods for read-only viewsupdate, getAndUpdate, updateAndGet extension methods on MutableStateEmitterStreamEvent base interface and EventResolver for event transformationfeat(llc): Add optional sorting to updateWhere by @xsahil03x in #24
Full Changelog: v0.3.2...v0.3.3
partition method for splitting lists into two based on a filter conditioncompare parameter to updateWhere for optional sorting after updatesfeat(llc): Add insertAt to upsert for controlling insertion position by @xsahil03x in #21
insertAt to upsert for controlling insertion position by @xsahil03x in #21Full Changelog: v0.3.1...v0.3.2
LocationCoordinate, Distance, CircularRegion,
and BoundingBoxinsertAt parameter to upsert for controlling insertion position of new elementsAdded updateWhere method for updating elements matching a filter condition
updateWhere method for updating elements matching a filter conditionbatchReplace method for replacing multiple elements based on matching keysinsertUnique method for inserting elements ensuring uniqueness by key with optional sortingupdate parameter to upsert for custom merge logic when replacing existing elementsupdate parameter to batchReplace for custom merge logicupdate parameter to sortedUpsert for custom merge logic when replacing existing elementsStreamDioException.toClientException() not handling invalid JSON strings gracefullyFilterField now requires a value getter function Object? Function(T)
FilterField now requires a value getter function Object? Function(T)EqualOperator → Equal, AndOperator → And)Filter signature changed to Filter<T extends Object>matches(T other) method for client-side filtering with PostgreSQL-like semanticsSort comparator to handle incompatible types safelyAdded macOS, Windows and Linux support, alongside the existing Android, iOS and web. macOS requires 10.15 or later. Linux needs FFmpeg and libwebp dev
libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libwebp-dev.StreamThumbnailFormat.webp is not supported yet and fails with anUNSUPPORTED_FORMAT error, and headers is ignored — a remote video needingthumbnailFile and thumbnailFiles no longer take a thumbnailPath, and no longerXFile. Use XFile.saveTo to copy itXFile.readAsBytes on web.thumbnailFiles now throws if any video fails, instead of dropping it from thePlatformException with a code and message on everyException. On iOS, a failed thumbnailData used tofile:// video now resolves to the right file:file:///tmp/a%20b.mp4 used to look for a literal a%20b.mp4. macOS behaves theXFile now carries a file name, so XFile.saveTo savesclip.png instead of an unnamed file.Published to pub.dev: https://pub.dev/packages/stream_thumbnail/versions/0.2.0
AppLifecycleStateProvider to LifecycleStateProvider and AppLifecycleState to LifecycleStatekeepConnectionAliveInBackground option to ConnectionRecoveryHandlerunknown state to NetworkState and LifecycleState enumsonClose() not being called when disconnecting during connecting state- Initial release
Your coding agent can read these notes before it upgrades. Set up the MCP server →