about summary refs log tree commit diff
path: root/src/view
diff options
context:
space:
mode:
authorEric Bailey <git@esb.lol>2025-02-18 08:54:25 -0600
committerGitHub <noreply@github.com>2025-02-18 08:54:25 -0600
commita51fc8e434b63a3f85accbf1bd29a01397c4b057 (patch)
tree44be28fc8812c6d4e20f0784be3a558ede9283cb /src/view
parente2c0f78719a9e576ad18ef0e4657c63a3147efed (diff)
downloadvoidsky-a51fc8e434b63a3f85accbf1bd29a01397c4b057.tar.zst
`@atproto/api@next` integration (#7344)
* Bump SDK

* Use consistent type in profile query

* Omit  from constraint for profile shadow

* Replace isRecord with isValidRecord in QuoteEmbed

* Omit type from constraint for old ProfileCard

* Omit type from constraint in profile queries where appropriate

* Use correct type for update profile mutation

* Conslidate and fix check for isValidRecord in Post.tsx

* Replace isRecord with isValidRecord in PostThreadItem

* Remove redundant cast in PostThreadFollowBtn

* Ignore errors in DebugMod screen

* Use matching type in ProfileFollows screen

* Use matching type in ProfileFollowers screen

* Migrate to isValidRecord in PostFeedItem

* Use matching type if PostRepostedBy

* Omit type from constraint in avatar props

* Use matching types in NotificationFeedItem

* Todo

* Use isValidRecord in NotfyFeedItem

* Improve MediaPreview types

* Migrate another isValidRecord in NotificationFeedItem

* Migrate to isValidView in queries/util

* Migrate to isValidRecord in threadgate/util

* Fix types in threadgates

* Fix up types in starter-packs queries

* Todo

* Specify exact types in search-posts

* Use internal type util to align types

* Ditto last

* Migrate postgate/index

* Specify exact types in post-thread

* Use correct type in post-quotes

* FIX potential bug in post-thread

* Use correct type in post-feed

* Add correct type guards to notifications/feed

* Migrate a guard in notifications/util

* Migrate guard in Wizard/State

* [@next] Profile handling, migrate `ProfileCard` (#7347)

* Introduce new utils for profiles, migrate old ProfileCard

* Rename, reorg

* Add parseEmbed utils

* Expand AnyProfileView to include chat profile view, update post shadow to reflect this

* Cast for perf reasons

* Tighten up types now that we have AnyProfileView

* Add fastIsType util

* Use `assertDid`

Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com>

* Use util types

* Comment

* Use fastIsType where no validation was happening before

* suggestions (#7382)

* suggestions

* Revert unneeded changes

---------

Co-authored-by: Eric Bailey <git@esb.lol>

* Use new util

* Rename to dangerousIsType

* Convert object shape

* Use dangerous util

* Use dangerous util

* Use dangerous util, we can trust post records

* Use dangerous util

* Use AnyProfileVIew

* Convert object shape

* Clean up handling

* Patch moderateProfile to accept known profile views, to discuss

* Add AnyStarterPackView and related, implement in first usage

* Remove validation, fix type, fix ref

* Migrate over list-conversations

* Clarify intent behind precacheProfile and its unstable query cache

* Clean up unstable profile cache

* Fix types during label creation in PwiOptOut (#7346)

* Tighten types in queries/list

* Chat: use correct profile views

* Chat: fix log type check

* Chat: construct lexically correct shape, even though it's only internal usage

* Chat: use correct profile types

* Chat: fix type check in logs

* Starter: use correct profile types

* Starter: use correct profile types

* Starter: tighten types to match lex

* Any profile type will work in blocked-and-muted

* Use dangerous util

* Use dangerousIsType

* Update new ProfileCard to use AnyProfileView

* Use dangerousIsType

* Remove outdated todo

* Use correct profile type

* Use correct profile types

* Tighten up types

* Use dangerousIsType

* Chat: more type fixes

* Remove unused file

* Add a few  utils

* Remove unused file

* Ignore feedPost.__source

* Clean up types, leave validation in critical path

* Use dangerousIstype

* Use ANyProfileView

* Use isValidRecord

* Use dangerousIsType

* Fix types in ListCard

* Fix FeedInterstitials types

* Fix types in FeedCard

* Fix types in dms ReportDialog

* Fix types in SearchablePeopleList

* Fix bad type in composer opts

* Starter: ok these need to be loose too

* Clarify docs

Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com>

* Less code

Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com>

* Use package exports

Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com>

* Use package exports

* Bump sdk, update $Typed imports

* Format

* Format

* Fix weird TS error

* Remove patch

* Beter name

* It's memo, can validate

* Tighten up parseEmbed, dogfood

* Bump sdk

* Use asPredicate

* Loosen types a bit

* use asPredicate

* Fix types

* Use asPredicate

* Use asPredicate

* Use asPredicate

* Clean up upsertProfile types

* Use asPredicate

* Use Un util

* Fix types

* Use new AnyProfileView

* Use dangerousIsType

* Use asPredicate

* Use asPredicate

* Add fallback content-type to pass typecheck

* Clean up upsertProfile types

* Align types

* Use dangerousIsType

* Use dangerousIsType

* Use asPredicate

* Align types

* Convert findLast

* Align types

* Just ignore type errors and use findLast

* Rename atproto -> bsky

* Add validate util

* Fix type error

* Loosen types

* Export post

* rename atp bsky

* Remove unused code

* minor changes

* Bump deps

* Fix types

* Tighten back up loose check

* Tighten back up loose check

* Fix small bug

* Update comment

* Revert change

---------

Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com>
Co-authored-by: Matthieu Sieben <matthieu.sieben@gmail.com>
Diffstat (limited to 'src/view')
-rw-r--r--src/view/com/lists/ListMembers.tsx7
-rw-r--r--src/view/com/notifications/NotificationFeedItem.tsx18
-rw-r--r--src/view/com/post-thread/PostRepostedBy.tsx2
-rw-r--r--src/view/com/post-thread/PostThreadFollowBtn.tsx5
-rw-r--r--src/view/com/post-thread/PostThreadItem.tsx6
-rw-r--r--src/view/com/post/Post.tsx4
-rw-r--r--src/view/com/posts/PostFeedItem.tsx9
-rw-r--r--src/view/com/profile/FollowButton.tsx4
-rw-r--r--src/view/com/profile/ProfileCard.tsx12
-rw-r--r--src/view/com/profile/ProfileFollowers.tsx2
-rw-r--r--src/view/com/profile/ProfileFollows.tsx2
-rw-r--r--src/view/com/util/UserAvatar.tsx5
-rw-r--r--src/view/com/util/post-embeds/QuoteEmbed.tsx13
-rw-r--r--src/view/screens/DebugMod.tsx2
-rw-r--r--src/view/screens/Search/Search.tsx13
-rw-r--r--src/view/shell/desktop/LeftNav.tsx2
16 files changed, 68 insertions, 38 deletions
diff --git a/src/view/com/lists/ListMembers.tsx b/src/view/com/lists/ListMembers.tsx
index 0caae6701..31d2b5fb5 100644
--- a/src/view/com/lists/ListMembers.tsx
+++ b/src/view/com/lists/ListMembers.tsx
@@ -1,6 +1,6 @@
 import React, {useCallback} from 'react'
 import {Dimensions, StyleProp, View, ViewStyle} from 'react-native'
-import {AppBskyActorDefs, AppBskyGraphDefs} from '@atproto/api'
+import {AppBskyGraphDefs} from '@atproto/api'
 import {msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
@@ -11,6 +11,7 @@ import {useModalControls} from '#/state/modals'
 import {useListMembersQuery} from '#/state/queries/list-members'
 import {useSession} from '#/state/session'
 import {ListFooter} from '#/components/Lists'
+import * as bsky from '#/types/bsky'
 import {ProfileCard} from '../profile/ProfileCard'
 import {ErrorMessage} from '../util/error/ErrorMessage'
 import {Button} from '../util/forms/Button'
@@ -116,7 +117,7 @@ export function ListMembers({
   }, [fetchNextPage])
 
   const onPressEditMembership = React.useCallback(
-    (profile: AppBskyActorDefs.ProfileViewBasic) => {
+    (profile: bsky.profile.AnyProfileView) => {
       openModal({
         name: 'user-add-remove-lists',
         subject: profile.did,
@@ -131,7 +132,7 @@ export function ListMembers({
   // =
 
   const renderMemberButton = React.useCallback(
-    (profile: AppBskyActorDefs.ProfileViewBasic) => {
+    (profile: bsky.profile.AnyProfileView) => {
       if (!isOwner) {
         return null
       }
diff --git a/src/view/com/notifications/NotificationFeedItem.tsx b/src/view/com/notifications/NotificationFeedItem.tsx
index 1267ce089..84694fe3b 100644
--- a/src/view/com/notifications/NotificationFeedItem.tsx
+++ b/src/view/com/notifications/NotificationFeedItem.tsx
@@ -58,6 +58,7 @@ import * as MediaPreview from '#/components/MediaPreview'
 import {ProfileHoverCard} from '#/components/ProfileHoverCard'
 import {Notification as StarterPackCard} from '#/components/StarterPack/StarterPackCard'
 import {SubtleWebHover} from '#/components/SubtleWebHover'
+import * as bsky from '#/types/bsky'
 import {FeedSourceCard} from '../feeds/FeedSourceCard'
 import {Post} from '../post/Post'
 import {Link, TextLink} from '../util/Link'
@@ -71,7 +72,7 @@ const MAX_AUTHORS = 5
 const EXPANDED_AUTHOR_EL_HEIGHT = 35
 
 interface Author {
-  profile: AppBskyActorDefs.ProfileViewBasic
+  profile: AppBskyActorDefs.ProfileView
   href: string
   moderation: ModerationDecision
 }
@@ -264,7 +265,10 @@ let NotificationFeedItem = ({
 
     if (
       item.notification.author.viewer?.following &&
-      AppBskyGraphFollow.isRecord(item.notification.record)
+      bsky.dangerousIsType<AppBskyGraphFollow.Record>(
+        item.notification.record,
+        AppBskyGraphFollow.isRecord,
+      )
     ) {
       let followingTimestamp
       try {
@@ -521,7 +525,7 @@ function ExpandListPressable({
   }
 }
 
-function SayHelloBtn({profile}: {profile: AppBskyActorDefs.ProfileViewBasic}) {
+function SayHelloBtn({profile}: {profile: AppBskyActorDefs.ProfileView}) {
   const {_} = useLingui()
   const agent = useAgent()
   const navigation = useNavigation<NavigationProp>()
@@ -716,7 +720,13 @@ function ExpandedAuthorsList({
 
 function AdditionalPostText({post}: {post?: AppBskyFeedDefs.PostView}) {
   const pal = usePalette('default')
-  if (post && AppBskyFeedPost.isRecord(post?.record)) {
+  if (
+    post &&
+    bsky.dangerousIsType<AppBskyFeedPost.Record>(
+      post?.record,
+      AppBskyFeedPost.isRecord,
+    )
+  ) {
     const text = post.record.text
 
     return (
diff --git a/src/view/com/post-thread/PostRepostedBy.tsx b/src/view/com/post-thread/PostRepostedBy.tsx
index 2143bd9c2..c27e37f49 100644
--- a/src/view/com/post-thread/PostRepostedBy.tsx
+++ b/src/view/com/post-thread/PostRepostedBy.tsx
@@ -16,7 +16,7 @@ function renderItem({
   item,
   index,
 }: {
-  item: ActorDefs.ProfileViewBasic
+  item: ActorDefs.ProfileView
   index: number
 }) {
   return (
diff --git a/src/view/com/post-thread/PostThreadFollowBtn.tsx b/src/view/com/post-thread/PostThreadFollowBtn.tsx
index 9dc93916a..145e919f9 100644
--- a/src/view/com/post-thread/PostThreadFollowBtn.tsx
+++ b/src/view/com/post-thread/PostThreadFollowBtn.tsx
@@ -5,7 +5,7 @@ import {useLingui} from '@lingui/react'
 import {useNavigation} from '@react-navigation/native'
 
 import {logger} from '#/logger'
-import {Shadow, useProfileShadow} from '#/state/cache/profile-shadow'
+import {useProfileShadow} from '#/state/cache/profile-shadow'
 import {
   useProfileFollowMutationQueue,
   useProfileQuery,
@@ -35,8 +35,7 @@ function PostThreadFollowBtnLoaded({
   const navigation = useNavigation()
   const {_} = useLingui()
   const {gtMobile} = useBreakpoints()
-  const profile: Shadow<AppBskyActorDefs.ProfileViewBasic> =
-    useProfileShadow(profileUnshadowed)
+  const profile = useProfileShadow(profileUnshadowed)
   const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue(
     profile,
     'PostThreadItem',
diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx
index 928ccd783..024629198 100644
--- a/src/view/com/post-thread/PostThreadItem.tsx
+++ b/src/view/com/post-thread/PostThreadItem.tsx
@@ -58,6 +58,7 @@ import {RichText} from '#/components/RichText'
 import {SubtleWebHover} from '#/components/SubtleWebHover'
 import {Text} from '#/components/Typography'
 import {WhoCanReply} from '#/components/WhoCanReply'
+import * as bsky from '#/types/bsky'
 
 export function PostThreadItem({
   post,
@@ -790,7 +791,10 @@ function BackdatedPostIndicator({post}: {post: AppBskyFeedDefs.PostView}) {
   const control = Prompt.usePromptControl()
 
   const indexedAt = new Date(post.indexedAt)
-  const createdAt = AppBskyFeedPost.isRecord(post.record)
+  const createdAt = bsky.dangerousIsType<AppBskyFeedPost.Record>(
+    post.record,
+    AppBskyFeedPost.isRecord,
+  )
     ? new Date(post.record.createdAt)
     : new Date(post.indexedAt)
 
diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx
index c87e361e1..2645237ad 100644
--- a/src/view/com/post/Post.tsx
+++ b/src/view/com/post/Post.tsx
@@ -28,6 +28,7 @@ import {atoms as a} from '#/alf'
 import {ProfileHoverCard} from '#/components/ProfileHoverCard'
 import {RichText} from '#/components/RichText'
 import {SubtleWebHover} from '#/components/SubtleWebHover'
+import * as bsky from '#/types/bsky'
 import {ContentHider} from '../../../components/moderation/ContentHider'
 import {LabelsOnMyPost} from '../../../components/moderation/LabelsOnMe'
 import {PostAlerts} from '../../../components/moderation/PostAlerts'
@@ -53,8 +54,7 @@ export function Post({
   const moderationOpts = useModerationOpts()
   const record = useMemo<AppBskyFeedPost.Record | undefined>(
     () =>
-      AppBskyFeedPost.isRecord(post.record) &&
-      AppBskyFeedPost.validateRecord(post.record).success
+      bsky.validate(post.record, AppBskyFeedPost.validateRecord)
         ? post.record
         : undefined,
     [post],
diff --git a/src/view/com/posts/PostFeedItem.tsx b/src/view/com/posts/PostFeedItem.tsx
index 4b18c470a..13c243c0a 100644
--- a/src/view/com/posts/PostFeedItem.tsx
+++ b/src/view/com/posts/PostFeedItem.tsx
@@ -47,6 +47,7 @@ import {AppModerationCause} from '#/components/Pills'
 import {ProfileHoverCard} from '#/components/ProfileHoverCard'
 import {RichText} from '#/components/RichText'
 import {SubtleWebHover} from '#/components/SubtleWebHover'
+import * as bsky from '#/types/bsky'
 import {Link, TextLink, TextLinkOnWebOnly} from '../util/Link'
 import {AviFollowButton} from './AviFollowButton'
 
@@ -232,8 +233,9 @@ let FeedItemInner = ({
    * If `post[0]` in this slice is the actual root post (not an orphan thread),
    * then we may have a threadgate record to reference
    */
-  const threadgateRecord = AppBskyFeedThreadgate.isRecord(
+  const threadgateRecord = bsky.dangerousIsType<AppBskyFeedThreadgate.Record>(
     rootPost.threadgate?.record,
+    AppBskyFeedThreadgate.isRecord,
   )
     ? rootPost.threadgate.record
     : undefined
@@ -461,7 +463,10 @@ let PostContent = ({
   })
   const additionalPostAlerts: AppModerationCause[] = React.useMemo(() => {
     const isPostHiddenByThreadgate = threadgateHiddenReplies.has(post.uri)
-    const rootPostUri = AppBskyFeedPost.isRecord(post.record)
+    const rootPostUri = bsky.dangerousIsType<AppBskyFeedPost.Record>(
+      post.record,
+      AppBskyFeedPost.isRecord,
+    )
       ? post.record?.reply?.root?.uri || post.uri
       : undefined
     const isControlledByViewer =
diff --git a/src/view/com/profile/FollowButton.tsx b/src/view/com/profile/FollowButton.tsx
index ff58dc945..656ed914a 100644
--- a/src/view/com/profile/FollowButton.tsx
+++ b/src/view/com/profile/FollowButton.tsx
@@ -1,10 +1,10 @@
 import {StyleProp, TextStyle, View} from 'react-native'
-import {AppBskyActorDefs} from '@atproto/api'
 import {msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
 import {Shadow} from '#/state/cache/types'
 import {useProfileFollowMutationQueue} from '#/state/queries/profile'
+import * as bsky from '#/types/bsky'
 import {Button, ButtonType} from '../util/forms/Button'
 import * as Toast from '../util/Toast'
 
@@ -18,7 +18,7 @@ export function FollowButton({
 }: {
   unfollowedType?: ButtonType
   followedType?: ButtonType
-  profile: Shadow<AppBskyActorDefs.ProfileViewBasic>
+  profile: Shadow<bsky.profile.AnyProfileView>
   labelStyle?: StyleProp<TextStyle>
   logContext: 'ProfileCard' | 'StarterPackProfilesList'
   onFollow?: () => void
diff --git a/src/view/com/profile/ProfileCard.tsx b/src/view/com/profile/ProfileCard.tsx
index f710d7b4e..bd09d6514 100644
--- a/src/view/com/profile/ProfileCard.tsx
+++ b/src/view/com/profile/ProfileCard.tsx
@@ -24,6 +24,7 @@ import {
   shouldShowKnownFollowers,
 } from '#/components/KnownFollowers'
 import * as Pills from '#/components/Pills'
+import * as bsky from '#/types/bsky'
 import {Link} from '../util/Link'
 import {Text} from '../util/text/Text'
 import {PreviewableUserAvatar} from '../util/UserAvatar'
@@ -41,12 +42,12 @@ export function ProfileCard({
   showKnownFollowers,
 }: {
   testID?: string
-  profile: AppBskyActorDefs.ProfileViewBasic
+  profile: bsky.profile.AnyProfileView
   noModFilter?: boolean
   noBg?: boolean
   noBorder?: boolean
   renderButton?: (
-    profile: Shadow<AppBskyActorDefs.ProfileViewBasic>,
+    profile: Shadow<bsky.profile.AnyProfileView>,
   ) => React.ReactNode
   onPress?: () => void
   style?: StyleProp<ViewStyle>
@@ -76,6 +77,7 @@ export function ProfileCard({
     showKnownFollowers &&
     shouldShowKnownFollowers(profile.viewer?.knownFollowers) &&
     moderationOpts
+  const hasDescription = 'description' in profile
 
   return (
     <Link
@@ -126,9 +128,9 @@ export function ProfileCard({
           <View style={styles.layoutButton}>{renderButton(profile)}</View>
         ) : undefined}
       </View>
-      {profile.description || knownFollowersVisible ? (
+      {hasDescription || knownFollowersVisible ? (
         <View style={styles.details}>
-          {profile.description ? (
+          {hasDescription && profile.description ? (
             <Text emoji style={pal.text} numberOfLines={4}>
               {profile.description as string}
             </Text>
@@ -139,7 +141,7 @@ export function ProfileCard({
                 a.flex_row,
                 a.align_center,
                 a.gap_sm,
-                !!profile.description && a.mt_md,
+                !!hasDescription && a.mt_md,
               ]}>
               <KnownFollowers
                 minimal
diff --git a/src/view/com/profile/ProfileFollowers.tsx b/src/view/com/profile/ProfileFollowers.tsx
index 3c0476929..d6b764656 100644
--- a/src/view/com/profile/ProfileFollowers.tsx
+++ b/src/view/com/profile/ProfileFollowers.tsx
@@ -17,7 +17,7 @@ function renderItem({
   item,
   index,
 }: {
-  item: ActorDefs.ProfileViewBasic
+  item: ActorDefs.ProfileView
   index: number
 }) {
   return (
diff --git a/src/view/com/profile/ProfileFollows.tsx b/src/view/com/profile/ProfileFollows.tsx
index 1cd65c74c..d67a7261a 100644
--- a/src/view/com/profile/ProfileFollows.tsx
+++ b/src/view/com/profile/ProfileFollows.tsx
@@ -17,7 +17,7 @@ function renderItem({
   item,
   index,
 }: {
-  item: ActorDefs.ProfileViewBasic
+  item: ActorDefs.ProfileView
   index: number
 }) {
   return (
diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx
index 2496f9d2a..934e8f50c 100644
--- a/src/view/com/util/UserAvatar.tsx
+++ b/src/view/com/util/UserAvatar.tsx
@@ -2,7 +2,7 @@ import React, {memo, useMemo} from 'react'
 import {Image, Pressable, StyleSheet, View} from 'react-native'
 import {Image as RNImage} from 'react-native-image-crop-picker'
 import Svg, {Circle, Path, Rect} from 'react-native-svg'
-import {AppBskyActorDefs, ModerationUI} from '@atproto/api'
+import {ModerationUI} from '@atproto/api'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
@@ -31,6 +31,7 @@ import {Link} from '#/components/Link'
 import {MediaInsetBorder} from '#/components/MediaInsetBorder'
 import * as Menu from '#/components/Menu'
 import {ProfileHoverCard} from '#/components/ProfileHoverCard'
+import * as bsky from '#/types/bsky'
 import {openCamera, openCropper, openPicker} from '../../../lib/media/picker'
 
 export type UserAvatarType = 'user' | 'algo' | 'list' | 'labeler'
@@ -55,7 +56,7 @@ interface EditableUserAvatarProps extends BaseUserAvatarProps {
 
 interface PreviewableUserAvatarProps extends BaseUserAvatarProps {
   moderation?: ModerationUI
-  profile: AppBskyActorDefs.ProfileViewBasic
+  profile: bsky.profile.AnyProfileView
   disableHoverCard?: boolean
   onBeforePress?: () => void
 }
diff --git a/src/view/com/util/post-embeds/QuoteEmbed.tsx b/src/view/com/util/post-embeds/QuoteEmbed.tsx
index cb549f7cd..e283a2eec 100644
--- a/src/view/com/util/post-embeds/QuoteEmbed.tsx
+++ b/src/view/com/util/post-embeds/QuoteEmbed.tsx
@@ -36,6 +36,7 @@ import {useSession} from '#/state/session'
 import {atoms as a, useTheme} from '#/alf'
 import {RichText} from '#/components/RichText'
 import {SubtleWebHover} from '#/components/SubtleWebHover'
+import * as bsky from '#/types/bsky'
 import {ContentHider} from '../../../../components/moderation/ContentHider'
 import {PostAlerts} from '../../../../components/moderation/PostAlerts'
 import {Link} from '../Link'
@@ -171,10 +172,14 @@ export function QuoteEmbed({
   const itemTitle = `Post by ${quote.author.handle}`
 
   const richText = React.useMemo(() => {
-    const text = AppBskyFeedPost.isRecord(quote.record) ? quote.record.text : ''
-    const facets = AppBskyFeedPost.isRecord(quote.record)
-      ? quote.record.facets
-      : undefined
+    if (
+      !bsky.dangerousIsType<AppBskyFeedPost.Record>(
+        quote.record,
+        AppBskyFeedPost.isRecord,
+      )
+    )
+      return undefined
+    const {text, facets} = quote.record
     return text.trim()
       ? new RichTextAPI({text: text, facets: facets})
       : undefined
diff --git a/src/view/screens/DebugMod.tsx b/src/view/screens/DebugMod.tsx
index 2224a4462..9774c644c 100644
--- a/src/view/screens/DebugMod.tsx
+++ b/src/view/screens/DebugMod.tsx
@@ -133,6 +133,7 @@ export const DebugModScreen = ({}: NativeStackScreenProps<
     })
     mockedProfile.did = did
     mockedProfile.avatar = 'https://bsky.social/about/images/favicon-32x32.png'
+    // @ts-expect-error ProfileViewBasic is close enough -esb
     mockedProfile.banner =
       'https://bsky.social/about/images/social-card-default-gradient.png'
     return mockedProfile
@@ -922,6 +923,7 @@ function MockAccountScreen({
           // @ts-ignore ProfileViewBasic is close enough -prf
           profile={profile}
           moderationOpts={moderationOpts}
+          // @ts-ignore ProfileViewBasic is close enough -esb
           descriptionRT={new RichText({text: profile.description as string})}
         />
       </ScreenHider>
diff --git a/src/view/screens/Search/Search.tsx b/src/view/screens/Search/Search.tsx
index 83503a706..b6d75b274 100644
--- a/src/view/screens/Search/Search.tsx
+++ b/src/view/screens/Search/Search.tsx
@@ -76,6 +76,7 @@ import {Earth_Stroke2_Corner0_Rounded as EarthIcon} from '#/components/icons/Glo
 import * as Layout from '#/components/Layout'
 import * as Menu from '#/components/Menu'
 import {account, useStorage} from '#/storage'
+import * as bsky from '#/types/bsky'
 
 function Loader() {
   return (
@@ -656,7 +657,7 @@ export function SearchScreenShell({
   )
 
   const updateProfileHistory = useCallback(
-    async (item: AppBskyActorDefs.ProfileViewBasic) => {
+    async (item: bsky.profile.AnyProfileView) => {
       const newAccountHistory = [
         item.did,
         ...accountHistory.filter(p => p !== item.did),
@@ -673,7 +674,7 @@ export function SearchScreenShell({
     [termHistory, setTermHistory],
   )
   const deleteProfileHistoryItem = useCallback(
-    async (item: AppBskyActorDefs.ProfileViewBasic) => {
+    async (item: AppBskyActorDefs.ProfileViewDetailed) => {
       setAccountHistory(accountHistory.filter(p => p !== item.did))
     },
     [accountHistory, setAccountHistory],
@@ -766,7 +767,7 @@ export function SearchScreenShell({
   )
 
   const handleProfileClick = React.useCallback(
-    (profile: AppBskyActorDefs.ProfileViewBasic) => {
+    (profile: bsky.profile.AnyProfileView) => {
       // Slight delay to avoid updating during push nav animation.
       setTimeout(() => {
         updateProfileHistory(profile)
@@ -1013,11 +1014,11 @@ function SearchHistory({
   onRemoveProfileClick,
 }: {
   searchHistory: string[]
-  selectedProfiles: AppBskyActorDefs.ProfileViewBasic[]
+  selectedProfiles: AppBskyActorDefs.ProfileViewDetailed[]
   onItemClick: (item: string) => void
-  onProfileClick: (profile: AppBskyActorDefs.ProfileViewBasic) => void
+  onProfileClick: (profile: AppBskyActorDefs.ProfileViewDetailed) => void
   onRemoveItemClick: (item: string) => void
-  onRemoveProfileClick: (profile: AppBskyActorDefs.ProfileViewBasic) => void
+  onRemoveProfileClick: (profile: AppBskyActorDefs.ProfileViewDetailed) => void
 }) {
   const {isMobile} = useWebMediaQueries()
   const pal = usePalette('default')
diff --git a/src/view/shell/desktop/LeftNav.tsx b/src/view/shell/desktop/LeftNav.tsx
index bb5de2eb4..522b51dba 100644
--- a/src/view/shell/desktop/LeftNav.tsx
+++ b/src/view/shell/desktop/LeftNav.tsx
@@ -220,7 +220,7 @@ function SwitchMenuItems({
   accounts:
     | {
         account: SessionAccount
-        profile?: AppBskyActorDefs.ProfileView
+        profile?: AppBskyActorDefs.ProfileViewDetailed
       }[]
     | undefined
   signOutPromptControl: DialogControlProps