NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev · #3385 most downloaded on pub.dev
The most famous and powerful Dart/Flutter library for Bluesky Social.
Last release today
08 Oct 2026
Release timing varies
gaps range from 8 days to 3 months
Nearly every release is documented
notes for 60 of the last 60 stable releases
1 version withdrawn
withdrawn after publishing
4 years old
246 releases · first in 2023
One column per quarter.
chore: Sync lexicons and regenerate sources
chore: Sync lexicons and regenerate sources (#2612)
app.bsky.embed.external#viewArticleapp.bsky.embed.external#viewArticlePublicationapp.bsky.embed.external#viewArticlePublicationThemeapp.bsky.embed.external#viewGalleryapp.bsky.embed.external#viewGalleryImageapp.bsky.embed.external#viewLivestreamapp.bsky.embed.getEmbedExternalView.output.dataapp.bsky.embed.record#viewRecord.opThreadPostCountapp.bsky.embed.record#viewRecord.opThreadPostIndexapp.bsky.unspecced.getAtmosphereExploreTab#announcementBannerapp.bsky.unspecced.getAtmosphereExploreTab#appCardapp.bsky.unspecced.getAtmosphereExploreTab#articleItemapp.bsky.unspecced.getAtmosphereExploreTab#galleryItemapp.bsky.unspecced.getAtmosphereExploreTab#livestreamItemapp.bsky.unspecced.getAtmosphereExploreTabapp.bsky.unspecced.getAtmosphereExploreTab#publicationItemtools.ozone.queue.defs#queueStats.closureTargetMetCounttools.ozone.queue.defs#queueStats.closureTargetMetRatetools.ozone.queue.defs#queueStats.closureTargetMissedCounttools.ozone.queue.defs#queueStats.closureTargetOverdueCounttools.ozone.queue.defs#queueStats.pendingCounttools.ozone.report.defs#historicalStats.closureTargetMetCounttools.ozone.report.defs#historicalStats.closureTargetMetRatetools.ozone.report.defs#historicalStats.closureTargetMissedCounttools.ozone.report.defs#historicalStats.closureTargetOverdueCounttools.ozone.report.defs#historicalStats.pendingCounttools.ozone.report.defs#liveStats.closureTargetMetCounttools.ozone.report.defs#liveStats.closureTargetMetRatetools.ozone.report.defs#liveStats.closureTargetMissedCounttools.ozone.report.defs#liveStats.closureTargetOverdueCounttools.ozone.report.defs#liveStats.pendingCounttools.ozone.report.defs#reportView.priorityLeveltools.ozone.report.defs#reportView.priorityScoretools.ozone.report.defs#reportView.priorityTargetMettools.ozone.report.defs#reportView.priorityTargetMinutestools.ozone.report.defs#reportView.resolutionTimeSecchore: Sync lexicons and regenerate sources
chore: Sync lexicons and regenerate sources (#2610)
tools.ozone.inbox.defs#actionView.policies changed type (array<string> -> array<ref(#policyView)>) (BREAKING)tools.ozone.inbox.defs#appealView.note (BREAKING)tools.ozone.inbox.defs#notificationtools.ozone.inbox.defs#notificationPreferencestools.ozone.inbox.defs#policyViewtools.ozone.inbox.defs#reportReftools.ozone.inbox.defs#reportsSummarytools.ozone.inbox.defs#standingReftools.ozone.inbox.defs#subjectReftools.ozone.inbox.defs#subjectView.isReadtools.ozone.inbox.defs#subjectViewDetailtools.ozone.inbox.getAccountStatustools.ozone.inbox.getActionedSubjecttools.ozone.inbox.getNotificationPreferencestools.ozone.inbox.getReporttools.ozone.inbox.getReport#reportViewtools.ozone.inbox.getReport#resolutionViewtools.ozone.inbox.getUnreadCounttools.ozone.inbox.getUnreadCount#unreadCountstools.ozone.inbox.listActionedSubjectstools.ozone.inbox.listNotificationstools.ozone.inbox.listReportstools.ozone.inbox.listReports#reportViewtools.ozone.inbox.putNotificationPreferencestools.ozone.inbox.updateSeentools.ozone.moderation.defs#modEventReport.appealActionIdtools.ozone.moderation.defs#modEventReport.appealActionTypetools.ozone.moderation.defs#modEventReport.appealLabeltools.ozone.moderation.defs#modEventReport.appealSubmittedBytools.ozone.server.getCapabilitiestools.ozone.server.getCapabilities#notificationConfigchore: Sync lexicons and regenerate sources
chore: Sync lexicons and regenerate sources (#2604)
app.bsky.unspecced.getOnboardingSuggestedStarterPacks.output.recIdStrapp.bsky.unspecced.getOnboardingSuggestedStarterPacksSkeleton.output.recIdStrapp.bsky.unspecced.getSuggestedFeeds.output.recIdStrapp.bsky.unspecced.getSuggestedFeedsSkeleton.output.recIdStrapp.bsky.unspecced.getSuggestedStarterPacks.output.recIdStrapp.bsky.unspecced.getSuggestedStarterPacksSkeleton.output.recIdStrchore: Sync lexicons and regenerate sources
chore: Sync lexicons and regenerate sources (#2603)
app.bsky.notification.getGroupedNotifications#contactMatchNotificationapp.bsky.notification.getGroupedNotifications#followBackNotificationapp.bsky.notification.getGroupedNotifications#followGroupapp.bsky.notification.getGroupedNotifications#followItemapp.bsky.notification.getGroupedNotifications#generatorLikeGroupapp.bsky.notification.getGroupedNotifications#generatorLikeItemapp.bsky.notification.getGroupedNotifications#groupapp.bsky.notification.getGroupedNotifications#likeGroupapp.bsky.notification.getGroupedNotifications#likeItemapp.bsky.notification.getGroupedNotifications#likeViaRepostGroupapp.bsky.notification.getGroupedNotifications#likeViaRepostItemapp.bsky.notification.getGroupedNotificationsapp.bsky.notification.getGroupedNotifications#mentionNotificationapp.bsky.notification.getGroupedNotifications#multiPostLikeGroupapp.bsky.notification.getGroupedNotifications#multiPostLikeItemapp.bsky.notification.getGroupedNotifications#quoteNotificationapp.bsky.notification.getGroupedNotifications#replyNotificationapp.bsky.notification.getGroupedNotifications#repostGroupapp.bsky.notification.getGroupedNotifications#repostItemapp.bsky.notification.getGroupedNotifications#repostViaRepostGroupapp.bsky.notification.getGroupedNotifications#repostViaRepostItemapp.bsky.notification.getGroupedNotifications#starterPackJoinedNotificationapp.bsky.notification.getGroupedNotifications#subscribedPostGroupapp.bsky.notification.getGroupedNotifications#subscribedPostItemapp.bsky.notification.getGroupedNotifications#unverifiedNotificationapp.bsky.notification.getGroupedNotifications#verifiedNotificationtools.ozone.report.defs#reportActivityView.activity changed type (union([#queueActivity, #assignmentActivity, #escalationActivity, #closeActivity, #reopenActivity, #noteActivity]) -> union([#queueActivity, #assignmentActivity, #unassignmentActivity, #escalationActivity, #closeActivity, #reopenActivity, #noteActivity])) (BREAKING)tools.ozone.report.defs#unassignmentActivitychore: Sync lexicons and regenerate sources
chore: Sync lexicons and regenerate sources (#2599)
app.bsky.feed.getListFeed.output.startCursorapp.bsky.feed.getListFeed.parameters.sinceapp.bsky.feed.getTimeline.output.startCursorapp.bsky.feed.getTimeline.parameters.sincechore: Sync lexicons and regenerate sources
chore: Sync lexicons and regenerate sources (#2598)
app.bsky.feed.getQuotes.parameters.sorttools.ozone.inbox.appealActionedSubject#actionReftools.ozone.inbox.appealActionedSubject#labelReftools.ozone.inbox.appealActionedSubjecttools.ozone.inbox.appealActionedSubject#takedownReftools.ozone.inbox.defs#actionViewtools.ozone.inbox.defs#appealViewtools.ozone.inbox.defs#enforcementViewtools.ozone.inbox.defs#subjectViewtools.ozone.queue.createQueue.input.recommendedLabelstools.ozone.queue.defs#queueView.recommendedLabelstools.ozone.queue.updateQueue.errors.ConflictingQueuetools.ozone.queue.updateQueue.input.recommendedLabelschore: Sync lexicons and regenerate sources
chore: Sync lexicons and regenerate sources (#2597)
app.bsky.feed.defs#feedViewPost.opThreadPostCountapp.bsky.feed.defs#feedViewPost.opThreadPostIndextools.ozone.report.defs#historicalStats.acknowledgedCounttools.ozone.report.defs#historicalStats.actionRatetools.ozone.report.defs#historicalStats.actionedCounttools.ozone.report.defs#historicalStats.ahtDurationSectools.ozone.report.defs#historicalStats.ahtSampleCounttools.ozone.report.defs#historicalStats.avgHandlingTimeSectools.ozone.report.defs#historicalStats.avgResolutionTimeSectools.ozone.report.defs#historicalStats.closedCounttools.ozone.report.defs#historicalStats.labelActionCounttools.ozone.report.defs#historicalStats.resolutionDurationSectools.ozone.report.defs#historicalStats.resolutionSampleCounttools.ozone.report.defs#historicalStats.tagActionCounttools.ozone.report.defs#historicalStats.takedownActionCounttools.ozone.report.defs#liveStats.acknowledgedCounttools.ozone.report.defs#liveStats.actionRatetools.ozone.report.defs#liveStats.actionedCounttools.ozone.report.defs#liveStats.ahtDurationSectools.ozone.report.defs#liveStats.ahtSampleCounttools.ozone.report.defs#liveStats.avgHandlingTimeSectools.ozone.report.defs#liveStats.avgResolutionTimeSectools.ozone.report.defs#liveStats.closedCounttools.ozone.report.defs#liveStats.escalatedCounttools.ozone.report.defs#liveStats.inboundCounttools.ozone.report.defs#liveStats.labelActionCounttools.ozone.report.defs#liveStats.resolutionDurationSectools.ozone.report.defs#liveStats.resolutionSampleCounttools.ozone.report.defs#liveStats.tagActionCounttools.ozone.report.defs#liveStats.takedownActionCounttools.ozone.report.defs#reportView.actionEventIdstools.ozone.report.getLiveStatstools.ozone.report.refreshStatschore: Sync lexicons and regenerate sources
chore: Sync lexicons and regenerate sources (#2595)
app.bsky.notification.getUnreadCount.parameters.priorityapp.bsky.notification.listNotifications.output.priorityapp.bsky.notification.listNotifications.parameters.priorityapp.bsky.notification.listNotifications.parameters.seenAtchore: Sync lexicons and regenerate sources
chore: Sync lexicons and regenerate sources (#2594)
app.bsky.notification.getUnreadCount.parameters.priority (BREAKING)app.bsky.notification.listNotifications.output.priority (BREAKING)app.bsky.notification.listNotifications.parameters.priority (BREAKING)chore: Sync lexicons and regenerate sources
chore: Sync lexicons and regenerate sources (#2585)
app.bsky.actor.defs#interestsPref.updatedAttools.ozone.moderation.getAccountPreferenceschore: Sync lexicons and regenerate sources
chore: Sync lexicons and regenerate sources (#2582)
app.bsky.graph.defs#listItemView.subjectOptedOutapp.bsky.graph.defs#listViewerState.referenceListOptOutapp.bsky.graph.referencelistoptoutMerge pull request #2578 from myConsciousness/chore/bluesky-release-2…
Merge pull request #2578 from myConsciousness/chore/bluesky-release-2…
GroupedNotificationReason.customFeedLike compares the AT URI's collection segment instead of searching the whole URI for app.bsky.feed.generator. An rkey may legally contain dots, so a like on at://<did>/app.bsky.feed.post/app.bsky.feed.generator is a like on a post, and the substring test grouped it as a feed like. If you relied on the old grouping for such a URI, it now groups as like. The check reads AtUri.collectionOrNull rather than collection (or the generated isFeedGenerator, which is built on it) because those throw when the URI has no collection segment, and the substring test being replaced never threw.GroupedNotificationReason says where customFeedLike comes from — it is synthesised here rather than mirrored from the lexicon — and that like therefore means "a like on something that is not a feed generator".GroupedNotificationReason is checked against lexicons/app/bsky/notification/listNotifications.json directly, so a value added there fails a test naming it instead of drifting unnoticed.Merge pull request #2568 from myConsciousness/fix/known-label-value-l…
Merge pull request #2568 from myConsciousness/fix/known-label-value-l…
KnownLabelValue was missing bot, which com.atproto.label.defs#labelValue lists among its knownValues. KnownLabelValue.valueOf('bot') answered null, so a caller using this enum to tell a global label value from a labeler-defined one got the wrong answer for it. Note that bot deliberately gets no entry in kLabels or kLabelDefinitions: the lexicon declares the value but not how to interpret it, and inventing a severity and a blur here would make this package decide moderation behaviour the protocol does not specify — so a bot label still flows through with no interpreted definition, exactly as before. This changes what the enum says, not what the moderation engine does.gore is documented as what it is — a value the lexicon has since dropped from knownValues, kept because labels already applied to existing content still carry it — rather than as a "deprecated alias".lexicons/com/atproto/label/defs.json directly, so a value added there fails a test naming it instead of drifting unnoticed.If you switch exhaustively over KnownLabelValue, this release adds a case you will need to handle. Shipped as a minor because that is how lexicon-driven enum additions have shipped here before, not because the risk is zero.
Merge pull request #2567 from myConsciousness/feat/bluesky-from-atpro…
Merge pull request #2567 from myConsciousness/feat/bluesky-from-atpro…
Bluesky.fromAtproto takes additionalHeaders, which sends extra headers on this client's app.bsky.* calls only and leaves the ATProto it was built from alone. Bluesky.fromSession has always taken headers; fromAtproto took none, so a caller who builds the ATProto themselves — the entire reason that constructor exists — could either put the header on the shared ATProto, where it also went out on com.atproto.* calls that were never meant to carry it, or build a second ATProto and lose the single-session guarantee. atproto-accept-labelers is the obvious case: the AppView only attaches labels from labelers named in that header, and it has no business on com.atproto.*.ServiceContext.withAdditionalHeaders on a derived context, matching BlueskyChat.fromAtproto. Derived rather than copied, so the session stays shared and only one refresh ever spends the single-use token; merged rather than spread, because header names are case-insensitive and a key-exact spread would leave Atproto-Proxy alongside a lowercase one for a custom getClient to emit twice. Omitting the parameter passes the original context through untouched, so nothing changes for an existing caller.chore: Sync lexicons and regenerate sources
chore: Sync lexicons and regenerate sources (#2565)
app.bsky.feed.defs#knownLikersapp.bsky.feed.defs#viewerState.knownLikerschore: Sync lexicons and regenerate sources
chore: Sync lexicons and regenerate sources (#2563)
app.bsky.actor.contentVisibilityDeclarationapp.bsky.embed.video.altapp.bsky.embed.video#view.altfeat: added app.bsky.video.abortUpload
app.bsky.video.abortUploadapp.bsky.video.defs#jobStatus.stateapp.bsky.video.finishUploadapp.bsky.video.getUploadStatusapp.bsky.video.startUploadapp.bsky.video.uploadPartchore: updated app.bsky.embed.video.video
app.bsky.embed.video.videofeat: added feed.buildPostText and feed.postText, which turn plain text into a faceted app.bsky.feed.post in one call. Getting this right by hand took
feed.buildPostText and feed.postText, which turn plain text into a faceted app.bsky.feed.post in one call. Getting this right by hand took three steps the docs had to spell out — format first (markdown links only become link facets after formatting), post the formatted text rather than the input (facet ranges are byte offsets into it, so the original string points every link at the wrong characters), and convert bluesky_text's facet maps into RichtextFacet models. buildPostText returns a PostText holding the formatted text and its facets together so the two cannot be separated by accident, and postText builds and publishes in one call.com.atproto.identity.resolveHandle over this client's transport. bluesky_text on its own opens its own HTTP connection to a default host, so an account on a self-hosted PDS resolved its mentions against the wrong server, and none of the client's configuration — service, timeout, retry policy, custom getClient, proxy headers — applied to that call.PostText.unresolvedHandles (or through postText's onUnresolvedHandles) instead of being silently dropped. It is not an error — the mention just stays plain text — but throwing from the callback aborts before the record is created, for an author who would rather fix a typo than publish a mention that renders as plain text.bluesky_text moves from a dev dependency to a runtime dependency. It brings no new transitive packages (xrpc, http and characters are already dependencies) and there is no cycle: bluesky_text does not depend on bluesky.chore: bump atproto to ^2.5.0, which adds Firehose and CursorStore to package:bluesky/firehose.dart.
atproto to ^2.5.0, which adds Firehose and CursorStore to package:bluesky/firehose.dart.fix: Bluesky.fromOAuthSession, BlueskyChat.fromOAuthSession and OzoneTool.fromOAuthSession pass their timeout through to the OAuthSessionManager they
Bluesky.fromOAuthSession, BlueskyChat.fromOAuthSession and OzoneTool.fromOAuthSession pass their timeout through to the OAuthSessionManager they build, so a hung restore or refresh is bounded by the timeout the caller asked for instead of running unbounded.feat: added tools.ozone.queue.createQueue.errors.InvalidRecommendedPolicies
tools.ozone.queue.createQueue.errors.InvalidRecommendedPoliciestools.ozone.queue.createQueue.input.recommendedPoliciestools.ozone.queue.defs#queueView.recommendedPoliciestools.ozone.queue.updateQueuetools.ozone.queue.updateQueue.errors.InvalidRecommendedPoliciestools.ozone.queue.updateQueue.input.recommendedPolicieschore: updated chat.bsky.group.createGroup.input.members
chat.bsky.group.createGroup.input.memberschore: updated app.bsky.actor.defs#viewerState.muted
app.bsky.actor.defs#viewerState.mutedapp.bsky.actor.defs#viewerState.mutedOnlyQuotepostsapp.bsky.actor.defs#viewerState.mutedOnlyRepostsapp.bsky.graph.getMutesapp.bsky.graph.muteActorapp.bsky.graph.muteActor.input.onlyQuotepostsapp.bsky.graph.muteActor.input.onlyRepostsapp.bsky.unspecced.defs#threadItemPost.opThreadapp.bsky.unspecced.defs#threadItemPost.opThreadPostCountapp.bsky.unspecced.defs#threadItemPost.opThreadPostIndexapp.bsky.video.defs#jobStatus.failureCodefeat: added tools.ozone.report.closeReports
tools.ozone.report.closeReportstools.ozone.report.createActivity.errors.ReportNotFoundtools.ozone.report.createActivity.input.eventIdtools.ozone.report.createActivity.input.reportId is now optionalatproto to ^2.4.1chore: updated app.bsky.draft.createDraft.output.id
app.bsky.draft.createDraft.output.idfeat: ThreadVerificationException now carries the thread's rkeys and uris, and reports a response without the optional results array as inconclusive r
ThreadVerificationException now carries the thread's rkeys and uris, and reports a response without the optional results array as inconclusive rather than as a plain failure. applyWrites is atomic, so the exception is only ever raised after the thread is committed, and createThreadAtomic builds the batch internally — the record keys that make the posts findable used to die with it, leaving a published thread reported as a hard failure nothing could act on. A server that omits results has contradicted nothing, and inconclusive says so: the thread is there, and a feed.post.get on the first of uris confirms it.bluesky.video.uploadVideo now throws a StateError when the client has no authenticated account, instead of sending did= and surfacing whatever the video service makes of it — after the whole video has been uploaded. A caller supplying its own did in $parameters is unaffected.bluesky.video.uploadVideoAndAwait now rejects a zero or negative pollInterval or timeout with an ArgumentError before anything is sent. A non-positive interval polled video.bsky.app as fast as it answered, for as long as the job ran.bluesky.video.uploadVideoAndAwait no longer calls onProgress once its timeout has expired. A status that arrived while the budget ran out was still reported, so a caller that had already been handed VideoUploadTimeoutException saw one last progress event for an upload it had given up on.ozoneDid to every OzoneTool factory, naming the Ozone instance tools.ozone.* should be routed to. OzoneTool was the only client that set no proxy header of its own and told the caller to supply one, but a caller-supplied atproto-proxy belongs to the shared context, so it rode on app.bsky.* and com.atproto.* as well — leaving fromAtproto a choice between misrouting the timeline and reintroducing the single-use refresh token race it exists to remove. OzoneTool now derives a context of its own, as BlueskyChat already did, and the header follows tools.ozone.* alone. #atproto_labeler is appended unless ozoneDid already names a service; omitting ozoneDid adopts the context unchanged, as before.BlueskyChat's own. The two were merged key-exactly, so Atproto-Proxy and atproto-proxy both reached the request; package:http happened to collapse them in the chat client's favour, but a custom GetClient/PostClient forwarding the raw map emitted both and a server reading the first sent DM listing and sending to whatever service the caller had named.nsfw, gore and suggestive were remapped only on unscoped preferences, so the same preference with a labelerDid was filed under a key nothing ever reads — a labeler-scoped "hide nsfw" was silently a no-op while the unscoped one worked.ActorGetPreferencesOutput.getModerationPrefs no longer lists an app labeler twice when the user also subscribes to it. The app labelers are seeded first so that prefs scoped to them attach, and a labelersPref entry for one of them now reuses that seeded entry instead of appending a duplicate to ModerationPrefs.labelers.GroupBy.hour and GroupBy.minute bucket on UTC components with a UTC key. The bucket key was built from a local DateTime, so on a DST spring-forward date a local wall-clock time that does not exist normalized upward and collapsed two distinct UTC hours into one bucket.indexedAt are returned in the order they were created. List.sort is not stable, so beyond a handful of groups the ties came back in an arbitrary order.NotificationsGrouperConfig.uniqueAuthors, which controls whether a group keeps at most one entry per author. The check used to be nested inside the time-window branch, so a custom config with window: null silently collapsed repeated notifications from one author. It now stands on its own and window governs the time window and nothing else. Defaults to true for custom configs; both shipped presets keep their current behavior (official on, lenient off).NotificationsGrouper, NotificationsExtension.group and NotificationsGrouperConfig.window no longer describe the time window as sliding. The anchor is the notification that opened the group and is fixed for the group's lifetime; since notifications arrive newest first it is normally the group's newest.feat: added Bluesky.fromAtproto, BlueskyChat.fromAtproto and OzoneTool.fromAtproto, which drive their services from an ATProto the caller already owns
Bluesky.fromAtproto, BlueskyChat.fromAtproto and OzoneTool.fromAtproto, which drive their services from an ATProto the caller already owns instead of building a new one. Every factory used to build its own, and each of those owned a context holding its own copy of the session — so an app needing more than one client for the same account held two copies of one session. Refresh tokens are single-use, so those copies raced the moment the access token expired: the context that noticed first spent the token, and the other's refresh was rejected, surfacing as an UnauthorizedException the caller did nothing to provoke. Passing one ATProto to each client gives them one session, one deduplicated refresh, and one onSessionUpdated stream.actorDid to Bluesky, BlueskyChat and OzoneTool, so the authenticated actor can be read without branching on the auth kind.bluesky.feed.createThreadAtomic, which publishes a whole thread in a single com.atproto.repo.applyWrites commit. Record keys and reply CIDs are computed locally, so every post references the previous one without waiting for it to be written, and the thread is committed atomically rather than post by post. Also added ThreadPost, ThreadBatch, CreatedThread and ThreadVerificationException; ThreadBatch builds and verifies a batch without a client, exposing the record keys before the write and allowing an extra write — an app.bsky.feed.threadgate, say — in the same commit. Bluesky.feed is now FeedServiceImpl, a subclass of FeedService matching Bluesky.video; existing calls are unaffected.VideoServiceImpl.uploadVideoAndAwait, which uploads a video and resolves with the resulting blob once the processing job terminates, polling getJobStatus at a caller-chosen interval and bounding the whole operation with a timeout. Added VideoUploadException with VideoJobFailedException, VideoJobMissingBlobException and VideoUploadTimeoutException, so a caller can tell a video the server rejected from one it gave up waiting for, and can show the server's own reason. A job that completes without a blob is reported as a failure rather than a success.BlueskyChat's own atproto no longer sends the atproto-proxy chat header on the com.atproto.* calls made through it. The header identifies the chat service and belongs to chat.bsky.* alone; routing an identity or server call to it was unintended. BlueskyChat.headers is unchanged, and chat calls still carry the header.OAuthSessionManager is what makes clients share a session, and that fromOAuthSession mints a fresh manager per call — two managers restored from one OAuthSession revoke each other rather than sharing.atproto_core to ^2.3.0 and atproto to ^2.3.0 (dev: bluesky_text ^1.6.0).feat: added app.bsky.ageassurance.defs#configRegion.platforms
app.bsky.ageassurance.defs#configRegion.platformsapp.bsky.notification.listNotifications#notification.starterPackchore: widen atproto to ^2.2.1 and atproto_core to ^2.2.0.
atproto to ^2.2.1 and atproto_core to ^2.2.0.fix: chat.bsky.* and tools.ozone.* calls now refresh an expired access token instead of throwing UnauthorizedException. v2.1.2 described this as cover
chat.bsky.* and tools.ozone.* calls now refresh an expired access token instead of throwing UnauthorizedException. v2.1.2 described this as covering chat.bsky.*, but only Bluesky was changed: BlueskyChat.fromSession and OzoneTool.fromSession each still built a standalone ServiceContext with no refresh hook, so every call through chat.convo / chat.actor / the ozone services surfaced an expired token as an error. Both now drive their services from the context owned by their nested ATProto, as Bluesky already did — the proxy headers that route those calls are preserved, since the nested client is built with them.onSessionUpdated to Bluesky, BlueskyChat and OzoneTool, surfacing the refreshed session so callers can re-persist it. Refresh tokens are single-use, so an app that keeps persisting the session it built the client with stores a spent token and is signed out on next launch.atproto to ^2.2.0 and atproto_core to ^2.1.0.fix: app.bsky.* and chat.bsky.* calls now refresh an expired access token instead of throwing UnauthorizedException. Bluesky.fromSession built a secon
app.bsky.* and chat.bsky.* calls now refresh an expired access token instead of throwing UnauthorizedException. Bluesky.fromSession built a second ServiceContext for those services and never gave it the refresh hook, so only calls made through bsky.atproto recovered from an expired token. Every factory now shares the context owned by the nested ATProto, which also makes bsky.session reflect a refresh — previously it kept returning the spent credentials, so persisting it signed the user out on next launch. The OAuth factories were unaffected, since both contexts already shared one OAuthSessionManager.atproto to ^2.1.0.feat: added app.bsky.graph.searchStarterPacksV2
app.bsky.graph.searchStarterPacksV2feat: notification grouping now matches the official Bluesky social-app by default. NotificationsGrouper / NotificationListNotificationsOutput.group()
NotificationsGrouper / NotificationListNotificationsOutput.group() now group six reasons (like, repost, follow, like-via-repost, repost-via-repost, subscribed-post), apply a 48h sliding window anchored on each group's newest item, separate follow-backs into their own groups, and mark a group unread if any of its notifications is unread. This changes the default grouping output (a behavior change); to keep the previous behavior, pass NotificationsGrouperConfig.lenient() (e.g. output.group(config: const NotificationsGrouperConfig.lenient())).NotificationsGrouperConfig (.official() / .lenient() / fully custom) controls groupable reasons, time window, follow-back separation, and the unread policy.NotificationsExtension.group() now accepts an optional config, and GroupBy / NotificationsExtension are now exported from package:bluesky/bluesky.dart.groupByHour / groupByMinute now use the official grouping default as well; for the legacy behavior with time bucketing, call group(by: GroupBy.hour(n), config: const NotificationsGrouperConfig.lenient()).bluesky_text to ^1.5.3.docs: added an OAuth authentication section to the README — Bluesky.fromOAuth(OAuthSessionManager) (also on BlueskyChat/OzoneTool), OAuthSessionManage
Bluesky.fromOAuth(OAuthSessionManager) (also on BlueskyChat/OzoneTool), OAuthSessionManager(oauth, sub:) / OAuthSessionManager.fromSession(restored), and the renamed oAuthSessionManager getter.bsky.atproto.sync.subscribeReposAsMessages() for typed messages.atproto_core to ^2.0.1 and atproto to ^2.0.1 (dev: bluesky_text ^1.5.2, atproto_oauth ^0.5.1).feat!: Bluesky.fromOAuth(OAuthSessionManager) (also on BlueskyChat/OzoneTool); fromOAuthSession(session, {oauthClient}) wraps a shared manager; oAuthS
Bluesky.fromOAuth(OAuthSessionManager) (also on BlueskyChat/OzoneTool); fromOAuthSession(session, {oauthClient}) wraps a shared manager; oAuthSession getter replaced by oAuthSessionManager.tools.ozone.queue.defs#queueView.subjectTypesretryConfig parameter (on Bluesky/BlueskyChat/OzoneTool) now accepts any RetryStrategy, not only RetryConfig, so callers can fully customize backoff and which failures retry. RetryStrategy/RetryContext/RetryReason are re-exported. By default a procedure (POST) is no longer retried after an ambiguous failure the server may already have applied (see atproto_core).labelerDid) are now applied only to the matching labeler and never leak into the global label defaults, and preferences scoped to an app labeler are honored instead of dropped — matching @atproto/api. Previously an orphaned scoped preference (e.g. for an unsubscribed labeler) could override the global defaults and, for example, unblur adult content.LinkPreview exposes cardyb's error/likelyType fields.did:web audience.tools extensions/utils.chore: tools.ozone.queue.defs#queueView.reportTypes is now optional
tools.ozone.queue.defs#queueView.reportTypes is now optionaltools.ozone.queue.defs#queueView.subjectTypes is now optionaltools.ozone.report.defs#reportView.isAutomatedchore: bump atproto to ^1.7.0, which exposes bsky.atproto.sync.subscribeReposAsMessages() — a Firehose subscription that yields already-decoded, typed
atproto to ^1.7.0, which exposes bsky.atproto.sync.subscribeReposAsMessages() — a Firehose subscription that yields already-decoded, typed messages instead of raw binary frames.fix!: rewrote the notification grouper as a typed O(n) implementation; notifications with a missing labels field (optional in the lexicon, common in p
labels field (optional in the lexicon, common in practice) no longer crash group()/_mergeLabels (B-1/B-2/B-8).verified, like-via-repost, subscribed-post, etc.); unknown reasons now fall back instead of throwing, so group() no longer crashes on live timelines (B-3).customFeedLike) actually merge (B-4).uploadVideo now uses ctx.repo, so it no longer crashes under an OAuth-authenticated client (session!.did was null) (B-13).decidePost now guards with validate() so a malformed federated record no longer throws (B-9/B-11).RangeError (was assert-only, so release builds silently misbehaved); labels are de-duped by value equality (B-5/B-6).OzoneTool.fromOAuthSession and oAuthSession getters for parity with sibling clients (B-14).lex_gen — knownValues+default fields are now non-nullable with their spec default (e.g. app.bsky.actor.defs#mutedWord.actorTarget → all, app.bsky.feed.getAuthorFeed.filter → posts_with_replies, tools.ozone.setting.listOptions.scope → instance); the corresponding hasX getters were removed and the moderation engine adapted accordingly (G-18).atproto to ^1.6.0, atproto_core to ^1.3.0, and bluesky_text to ^1.4.0.feat: added the deprecated gore alias for graphic-media to the known label definitions (KnownLabelValue.gore), matching the official label defs.
Aligned the client-side moderation engine with the official @atproto/api implementation:
moderateUserList now delegates to decideUserList instead of recursing into itself (previously caused a StackOverflowError).decideUserList no longer crashes on ListView subjects and now merges the creator's account/profile decisions, matching the official implementation.ModerationCauseSource.labeler) instead of always to the user.getInterpretedLabelValueDefinitions now defaults adultOnly to false (previously true), so labeler-defined labels are no longer adult-gated unless declared.getLabelerHeaders now appends ;redact only to app labelers (Bluesky's official labeler), matching the official atproto-accept-labelers header behavior. Subscribed labelers are sent without parameters.gore alias for graphic-media to the known label definitions (KnownLabelValue.gore), matching the official label defs.expiresAt (expired words are ignored) and actorTarget: exclude-following (pass the post author via the new actor parameter).matchMuteWords and MuteWordMatch, mirroring the official API. ModerationCauseMuteWord now carries the matches that triggered it.and/or no longer matches andor), and all tag facet features are considered (previously only the first per facet).moderatePost now scans app.bsky.embed.gallery alt texts and applies exclude-following via the post/quote author.moderateStatus / decideStatus for live status (app.bsky.actor.defs#statusView) moderation.ModerationBehaviors — a configuration object on ModerationOpts.behaviors that lets users customize block/mute/mute-word/hide behaviors and global label definitions without forking the engine. Defaults replicate the official logic.kBlockBehavior / kMuteBehavior / kMuteWordBehavior / kHideBehavior constants in favor of the typed kDefault*Behaviors maps.atproto and atproto_core.chore: deprecated chat preferences in app.bsky.notification.defs and app.bsky.notification.putPreferencesV2 in favor of chat.bsky.notification prefere…
app.bsky.feed.searchPostsV2 endpoint.chat.bsky.notification.getPreferences and chat.bsky.notification.putPreferences endpoints.chat.bsky.notification.defs#preferences and #chatPreference.isBetaUser to app.bsky.actor.defs#bskyAppStatePref.additionalVerificationMethods to app.bsky.ageassurance.defs.app.bsky.notification.defs and app.bsky.notification.putPreferencesV2 in favor of chat.bsky.notification preferences.app.bsky.embed.gallery embed (#image, #view, #viewImage).chat.bsky.convo.getUnreadCounts endpoint.chat.bsky.convo.defs#replyRef for message reply references.chat.bsky.group.defs#disabledJoinLinkPreviewView and #invalidJoinLinkPreviewView.tools.ozone.report.queryActivities endpoint.app.bsky.draft.defs#draftEmbedGallery correctly. Its items is now List<UDraftEmbedGalleryItems>; previously it referenced a non-existent file and failed to compile.com.germnetwork.declaration record in RepoCommitHandler and re-export it from atproto.- core: generated code.
- core: generated code.
- core: generated code.
- core: generated code.
- core: generated code.
- core: generated code.
fix: optional jwt scope and auth identity.
- chore: Sync Lexicon Data. - (#2217) - (#2219) - (#2222) - (#2225) - (#2228) - (#2230) - (#2233) - (#2237) - (#2238) - (#2239) - (#2243) - (#2244) -
- chore: Sync Lexicon Data. - (#2173) - (#2175) - (#2177) - fix: Codegen errors.
Fix typo causing crash in moderation code.
FIX: Fixed type compatibility issues with AtUri parameters
IMPROVEMENT: Enhanced union type classes with sealed class implementation
sealed classes instead of abstract classesfeat: Merged #2150 - Added pronouns field support to actor profiles
pronouns field to app.bsky.actor.defs#profileViewDetailed for displaying user pronouns in detailed profile viewspronouns field to app.bsky.actor.profile record for storing user pronouns in profile datafeat: Merged #2143 - Added onboarding suggested starter packs support
getOnboardingSuggestedStarterPacks endpoint for retrieving suggested starter packs during onboardinggetOnboardingSuggestedStarterPacksSkeleton endpoint for skeleton data of suggested starter packsUnspeccedService for improved user onboarding flowfeat: Merged #2137 - Added comprehensive Ozone moderation and administration services
tools.ozone.communication.* endpointstools.ozone.hosting.* endpointstools.ozone.moderation.* endpointstools.ozone.safelink.* endpointstools.ozone.server.* endpointstools.ozone.set.* endpointstools.ozone.setting.* endpointstools.ozone.signature.* endpointstools.ozone.team.* endpointstools.ozone.verification.* endpointspronouns field to app.bsky.actor.defs#profileViewDetailed and app.bsky.actor.profile recordwebsite field to app.bsky.actor.defs#profileViewDetailed and app.bsky.actor.profile recordMIGRATION: Updated to use the consolidated at_primitives package for all AT Protocol primitive types.
at_primitives package for all AT Protocol primitive types.at_primitives.feat: Version bump to v1.1.0 to reflect significant new functionality
atproto: ^1.1.0 for compatibility with latest AT Protocol featuresfeat: Added OzoneTool client for comprehensive tools.ozone.* API support
tools.ozone.* API support
OzoneTool class provides access to all Ozone moderation and administrative servicespackage:bluesky/ozone.dart import for modular usagecom.atproto.temp.dereferenceScope endpoint for temporary scope dereferencingtools.ozone.moderation.defs.revokeAccountCredentialsEvent for account credential revocationYour coding agent can read these notes before it upgrades. Set up the MCP server →