[SDK] Adopt @bsky.app/sdk and migrate RichText (#11369)

This commit is contained in:
Samuel Newman
2026-08-13 22:26:18 +03:00
committed by GitHub
parent d991118215
commit f6a22c4f05
47 changed files with 231 additions and 124 deletions
@@ -1,12 +1,7 @@
import {useCallback, useEffect, useMemo, useState} from 'react'
import {LayoutAnimation, View} from 'react-native'
import {
AppBskyFeedPost,
AppBskyRichtextFacet,
AtUri,
moderatePost,
RichText as RichTextAPI,
} from '@atproto/api'
import {AppBskyFeedPost, AtUri, moderatePost} from '@atproto/api'
import {RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
import {Trans, useLingui} from '@lingui/react/macro'
import {type RouteProp, useNavigation, useRoute} from '@react-navigation/native'
@@ -16,6 +11,7 @@ import {
type CommonNavigatorParams,
type NavigationProp,
} from '#/lib/routes/types'
import {asSdkFacets} from '#/lib/strings/rich-text-helpers'
import {
convertBskyAppUrlIfNeeded,
getChatInviteCodeFromUrl,
@@ -36,6 +32,7 @@ import {ContentHider} from '#/components/moderation/ContentHider'
import {PostAlerts} from '#/components/moderation/PostAlerts'
import {RichText} from '#/components/RichText'
import {Text} from '#/components/Typography'
import {app} from '#/lexicons'
import * as bsky from '#/types/bsky'
/**
@@ -106,7 +103,7 @@ export function useExtractEmbedFromFacets(
for (const facet of rt.facets ?? []) {
for (const feature of facet.features) {
if (
AppBskyRichtextFacet.isLink(feature) &&
bsky.isType(app.bsky.richtext.facet.link, feature) &&
(isBskyPostUrl(feature.uri) || isBskyChatInviteUrl(feature.uri))
) {
uriFromFacet = feature.uri
@@ -176,7 +173,7 @@ function MessageInputPostEmbed({
return {
rt: new RichTextAPI({
text: post.record.text,
facets: post.record.facets,
facets: asSdkFacets(post.record.facets),
}),
record: post.record,
}
@@ -25,13 +25,12 @@ import {scheduleOnRN} from 'react-native-worklets'
import {
type $Typed,
type AppBskyEmbedRecord,
AppBskyRichtextFacet,
ChatBskyConvoDefs,
type ChatBskyEmbedJoinLink,
ChatBskyGroupDefs,
RichText,
} from '@atproto/api'
import {useScrollEdgeEffectRef} from '@bsky.app/expo-scroll-edge-effect'
import {RichText} from '@bsky.app/sdk/richtext'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
import {mergeRefs} from '#/lib/merge-refs'
@@ -52,7 +51,7 @@ import {type ConvoState, ConvoStatus} from '#/state/messages/convo/types'
import {useGetJoinLinkPreview} from '#/state/queries/join-links'
import {useGetPost} from '#/state/queries/post'
import {createEmbedViewRecordFromPost} from '#/state/queries/postgate/util'
import {useAgent, useSession} from '#/state/session'
import {useAppviewClient, useSession} from '#/state/session'
import {List, type ListMethods} from '#/view/com/util/List'
import {MessageComposer} from '#/screens/Messages/components/MessageComposer'
import {MessageListError} from '#/screens/Messages/components/MessageListError'
@@ -71,6 +70,8 @@ import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography'
import {useAnalytics} from '#/analytics'
import {IS_ANDROID, IS_NATIVE, IS_WEB} from '#/env'
import {app} from '#/lexicons'
import * as bsky from '#/types/bsky'
import {ChatStatusInfo} from './ChatStatusInfo'
import {groupSystemMessages, type RenderItem} from './groupSystemMessages'
import {InviteLinkDialogProvider} from './InviteLinkDialogProvider'
@@ -144,7 +145,11 @@ export function MessagesList({
}) {
const ax = useAnalytics()
const convoState = useConvoActive()
const agent = useAgent()
/*
* Facet/mention resolution is an appview job - it resolves handles through
* the appview, and the public fallback keeps it working when logged out.
*/
const appviewClient = useAppviewClient()
const {hasSession, currentAccount} = useSession()
const getPost = useGetPost()
const getJoinLinkPreview = useGetJoinLinkPreview()
@@ -550,7 +555,8 @@ export function MessagesList({
const linkFacet = rt.facets?.find(facet =>
facet.features.find(
feature =>
AppBskyRichtextFacet.isLink(feature) && predicate(feature.uri),
bsky.isType(app.bsky.richtext.facet.link, feature) &&
predicate(feature.uri),
),
)
if (linkFacet) {
@@ -617,7 +623,7 @@ export function MessagesList({
replyTo = {messageId: reply.id}
}
await rt.detectFacets(agent)
await rt.detectFacets(appviewClient)
rt = shortenLinks(rt)
rt = stripInvalidMentions(rt)
@@ -667,7 +673,7 @@ export function MessagesList({
}
},
[
agent,
appviewClient,
convoState,
getPost,
getJoinLinkPreview,
@@ -5,8 +5,8 @@ import {
AppBskyFeedPost,
type AppBskyFeedThreadgate,
AtUri,
RichText as RichTextAPI,
} from '@atproto/api'
import {RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
import {Plural, Trans, useLingui} from '@lingui/react/macro'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
@@ -14,6 +14,7 @@ import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
import {makeProfileLink} from '#/lib/routes/links'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {sanitizeHandle} from '#/lib/strings/handles'
import {asSdkFacets} from '#/lib/strings/rich-text-helpers'
import {niceDate} from '#/lib/strings/time'
import {
POST_TOMBSTONE,
@@ -199,7 +200,7 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({
() =>
new RichTextAPI({
text: record.text,
facets: record.facets,
facets: asSdkFacets(record.facets),
}),
[record],
)
@@ -4,14 +4,15 @@ import {
type AppBskyFeedDefs,
type AppBskyFeedThreadgate,
AtUri,
RichText as RichTextAPI,
} from '@atproto/api'
import {RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
import {Trans} from '@lingui/react/macro'
import {MAX_POST_LINES} from '#/lib/constants'
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
import {makeProfileLink} from '#/lib/routes/links'
import {countLines} from '#/lib/strings/helpers'
import {asSdkFacets} from '#/lib/strings/rich-text-helpers'
import {
POST_TOMBSTONE,
type Shadow,
@@ -211,7 +212,7 @@ const ThreadItemPostInner = memo(function ThreadItemPostInner({
() =>
new RichTextAPI({
text: record.text,
facets: record.facets,
facets: asSdkFacets(record.facets),
}),
[record],
)
@@ -4,14 +4,15 @@ import {
type AppBskyFeedDefs,
type AppBskyFeedThreadgate,
AtUri,
RichText as RichTextAPI,
} from '@atproto/api'
import {RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
import {Trans} from '@lingui/react/macro'
import {MAX_POST_LINES} from '#/lib/constants'
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
import {makeProfileLink} from '#/lib/routes/links'
import {countLines} from '#/lib/strings/helpers'
import {asSdkFacets} from '#/lib/strings/rich-text-helpers'
import {
POST_TOMBSTONE,
type Shadow,
@@ -271,7 +272,7 @@ const ThreadItemTreePostInner = memo(function ThreadItemTreePostInner({
() =>
new RichTextAPI({
text: record.text,
facets: record.facets,
facets: asSdkFacets(record.facets),
}),
[record],
)
@@ -5,8 +5,8 @@ import {
type AppBskyLabelerDefs,
moderateProfile,
type ModerationOpts,
type RichText as RichTextAPI,
} from '@atproto/api'
import {type RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
import {msg, plural} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'
import {Plural, Trans} from '@lingui/react/macro'
@@ -5,8 +5,8 @@ import {
moderateProfile,
type ModerationDecision,
type ModerationOpts,
type RichText as RichTextAPI,
} from '@atproto/api'
import {type RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro'
+1 -1
View File
@@ -12,8 +12,8 @@ import {
type AppBskyLabelerDefs,
moderateProfile,
type ModerationOpts,
type RichText as RichTextAPI,
} from '@atproto/api'
import {type RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
import {useIsFocused} from '@react-navigation/native'
import {sanitizeHandle} from '#/lib/strings/handles'
@@ -1,12 +1,14 @@
import {useMemo} from 'react'
import {View} from 'react-native'
import {AppBskyGraphDefs, RichText as RichTextAPI} from '@atproto/api'
import {AppBskyGraphDefs} from '@atproto/api'
import {RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro'
import {useHaptics} from '#/lib/haptics'
import {makeListLink} from '#/lib/routes/links'
import {asSdkFacets} from '#/lib/strings/rich-text-helpers'
import {logger} from '#/logger'
import {useListBlockMutation, useListMuteMutation} from '#/state/queries/list'
import {
@@ -128,7 +130,7 @@ export function Header({
list.description
? new RichTextAPI({
text: list.description,
facets: list.descriptionFacets,
facets: asSdkFacets(list.descriptionFacets),
})
: undefined,
[list],
@@ -1,11 +1,8 @@
import {useMemo} from 'react'
import {Pressable, View} from 'react-native'
import {Image} from 'expo-image'
import {
type AppBskyUnspeccedDefs,
moderateProfile,
RichText as RichTextApi,
} from '@atproto/api'
import {type AppBskyUnspeccedDefs, moderateProfile} from '@atproto/api'
import {RichText as RichTextApi} from '@bsky.app/sdk/richtext'
import {Plural, Trans, useLingui} from '@lingui/react/macro'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
@@ -6,8 +6,8 @@ import {
AppBskyGraphStarterpack,
AtUri,
type ModerationOpts,
RichText as RichTextAPI,
} from '@atproto/api'
import {RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'
import {Plural, Trans} from '@lingui/react/macro'
@@ -24,6 +24,7 @@ import {
type NavigationProp,
} from '#/lib/routes/types'
import {cleanError} from '#/lib/strings/errors'
import {asSdkFacets} from '#/lib/strings/rich-text-helpers'
import {getStarterPackOgCard} from '#/lib/strings/starter-pack'
import {logger} from '#/logger'
import {updateProfileShadow} from '#/state/cache/profile-shadow'
@@ -418,7 +419,7 @@ function Header({
const richText = record.description
? new RichTextAPI({
text: record.description,
facets: record.descriptionFacets,
facets: asSdkFacets(record.descriptionFacets),
})
: undefined
+3 -2
View File
@@ -31,8 +31,8 @@ import {
AppBskyFeedPost,
AtUri,
type ModerationDecision,
RichText as RichTextAPI,
} from '@atproto/api'
import {RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
import {Trans, useLingui} from '@lingui/react/macro'
import {
type RouteProp,
@@ -58,6 +58,7 @@ import {
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {cleanError} from '#/lib/strings/errors'
import {sanitizeHandle} from '#/lib/strings/handles'
import {asSdkFacets} from '#/lib/strings/rich-text-helpers'
import {logger} from '#/logger'
import {useA11y} from '#/state/a11y'
import {
@@ -834,7 +835,7 @@ function Overlay({
: undefined
const richText = new RichTextAPI({
text: record?.text || '',
facets: record?.facets,
facets: asSdkFacets(record?.facets),
})
const handle = sanitizeHandle(post.author.handle, '@')