Compare commits

...

39 Commits

Author SHA1 Message Date
Eric Bailey ca119a30ba Rename, reorg 2025-01-06 14:16:38 -06:00
Eric Bailey af24b22c79 Introduce new utils for profiles, migrate old ProfileCard 2025-01-03 14:23:42 -06:00
Eric Bailey 1f5830f7fe Migrate guard in Wizard/State 2025-01-03 09:58:30 -06:00
Eric Bailey dace2a26f1 Migrate a guard in notifications/util 2025-01-03 09:48:22 -06:00
Eric Bailey 75fd73bda7 Add correct type guards to notifications/feed 2025-01-03 09:29:50 -06:00
Eric Bailey 50fc2d1dd5 Use correct type in post-feed 2025-01-03 09:26:45 -06:00
Eric Bailey 8a61a4297f FIX potential bug in post-thread 2025-01-03 09:25:53 -06:00
Eric Bailey 220ff2ff25 Use correct type in post-quotes 2025-01-03 09:23:54 -06:00
Eric Bailey 2cd8dd5edd Specify exact types in post-thread 2025-01-02 18:12:52 -06:00
Eric Bailey 62e4751439 Migrate postgate/index 2025-01-02 18:02:46 -06:00
Eric Bailey 13b89eae53 Ditto last 2025-01-02 17:58:51 -06:00
Eric Bailey fa5d130259 Use internal type util to align types 2025-01-02 17:49:34 -06:00
Eric Bailey 288ecbdd85 Specify exact types in search-posts 2025-01-02 17:43:38 -06:00
Eric Bailey bf08a3a708 Todo 2025-01-02 17:43:14 -06:00
Eric Bailey 0399e59443 Fix up types in starter-packs queries 2025-01-02 17:28:07 -06:00
Eric Bailey 69b9b14898 Fix types in threadgates 2025-01-02 17:21:51 -06:00
Eric Bailey df51b486f2 Migrate to isValidRecord in threadgate/util 2025-01-02 17:05:55 -06:00
Eric Bailey 19cb6aa605 Migrate to isValidView in queries/util 2025-01-02 17:05:13 -06:00
Eric Bailey 45171ab6ec Migrate another isValidRecord in NotificationFeedItem 2025-01-02 16:19:11 -06:00
Eric Bailey 517543f13a Improve MediaPreview types 2025-01-02 16:15:53 -06:00
Eric Bailey 1cf4f44de4 Use isValidRecord in NotfyFeedItem 2025-01-02 16:12:55 -06:00
Eric Bailey 1dbeff9852 Todo 2025-01-02 16:08:04 -06:00
Eric Bailey a1d4c1eadc Use matching types in NotificationFeedItem 2025-01-02 16:02:15 -06:00
Eric Bailey 44e2460a05 Omit type from constraint in avatar props 2025-01-02 16:01:51 -06:00
Eric Bailey fdfdeb5bdc Use matching type if PostRepostedBy 2025-01-02 15:12:46 -06:00
Eric Bailey 2009ea30db Migrate to isValidRecord in PostFeedItem 2025-01-02 15:12:13 -06:00
Eric Bailey 164d534c0e Use matching type in ProfileFollowers screen 2025-01-02 15:10:40 -06:00
Eric Bailey 0334813160 Use matching type in ProfileFollows screen 2025-01-02 15:10:01 -06:00
Eric Bailey 30de00cdfa Ignore errors in DebugMod screen 2025-01-02 15:08:35 -06:00
Eric Bailey 48ef08aa3e Remove redundant cast in PostThreadFollowBtn 2025-01-02 15:04:27 -06:00
Eric Bailey 11227f07d2 Replace isRecord with isValidRecord in PostThreadItem 2025-01-02 15:03:45 -06:00
Eric Bailey 87ce8bdcd4 Conslidate and fix check for isValidRecord in Post.tsx 2025-01-02 15:03:03 -06:00
Eric Bailey 069609e7f3 Use correct type for update profile mutation 2025-01-02 14:55:41 -06:00
Eric Bailey 8f62efcb61 Omit type from constraint in profile queries where appropriate 2025-01-02 14:54:25 -06:00
Eric Bailey 363e700681 Omit type from constraint for old ProfileCard 2025-01-02 14:31:50 -06:00
Eric Bailey f0c6224781 Replace isRecord with isValidRecord in QuoteEmbed 2025-01-02 10:51:47 -06:00
Eric Bailey b1f1098ff3 Omit from constraint for profile shadow 2025-01-02 10:24:00 -06:00
Eric Bailey c2f9d7c5b1 Use consistent type in profile query 2025-01-02 10:10:12 -06:00
Eric Bailey 803dbc49e2 Bump SDK 2025-01-02 10:09:50 -06:00
36 changed files with 208 additions and 154 deletions
+1 -1
View File
@@ -54,7 +54,7 @@
"icons:optimize": "svgo -f ./assets/icons"
},
"dependencies": {
"@atproto/api": "^0.13.21",
"@atproto/api": "0.14.0-next.1",
"@braintree/sanitize-url": "^6.0.2",
"@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet",
"@emoji-mart/react": "^1.1.1",
+5 -9
View File
@@ -6,6 +6,7 @@ import {
AppBskyEmbedImages,
AppBskyEmbedRecordWithMedia,
AppBskyEmbedVideo,
AppBskyFeedDefs,
} from '@atproto/api'
import {Trans} from '@lingui/macro'
@@ -22,17 +23,12 @@ export function Embed({
embed,
style,
}: {
embed?:
| AppBskyEmbedImages.View
| AppBskyEmbedRecordWithMedia.View
| AppBskyEmbedExternal.View
| AppBskyEmbedVideo.View
| {[k: string]: unknown}
embed?: AppBskyFeedDefs.PostView['embed']
style?: StyleProp<ViewStyle>
}) {
let media = AppBskyEmbedRecordWithMedia.isView(embed) ? embed.media : embed
if (AppBskyEmbedImages.isView(media)) {
if (AppBskyEmbedImages.isValidView(media)) {
return (
<Outer style={style}>
{media.images.map(image => (
@@ -44,7 +40,7 @@ export function Embed({
))}
</Outer>
)
} else if (AppBskyEmbedExternal.isView(media) && media.external.thumb) {
} else if (AppBskyEmbedExternal.isValidView(media) && media.external.thumb) {
let url: URL | undefined
try {
url = new URL(media.external.uri)
@@ -62,7 +58,7 @@ export function Embed({
)
}
}
} else if (AppBskyEmbedVideo.isView(media)) {
} else if (AppBskyEmbedVideo.isValidView(media)) {
return (
<Outer style={style}>
<VideoItem thumbnail={media.thumbnail} alt={media.alt} />
+4 -1
View File
@@ -126,7 +126,10 @@ export function Provider({
const {currentAccount} = useSession()
const createInitialState = (): State => {
if (starterPack && AppBskyGraphStarterpack.isRecord(starterPack.record)) {
if (
starterPack &&
AppBskyGraphStarterpack.isValidRecord(starterPack.record)
) {
return {
canNext: true,
currentStep: 'Details',
+1 -1
View File
@@ -35,7 +35,7 @@ const shadows: WeakMap<
const emitter = new EventEmitter()
export function useProfileShadow<
TProfileView extends AppBskyActorDefs.ProfileView,
TProfileView extends Omit<AppBskyActorDefs.ProfileView, '$type'>,
>(profile: TProfileView): Shadow<TProfileView> {
const [shadow, setShadow] = useState(() => shadows.get(profile))
const [prevPost, setPrevPost] = useState(profile)
+11 -7
View File
@@ -295,9 +295,11 @@ export function* findAllPostsInQueryData(
}
}
const quotedPost = getEmbeddedPost(item.subject?.embed)
if (quotedPost && didOrHandleUriMatches(atUri, quotedPost)) {
yield embedViewRecordToPostView(quotedPost!)
if (AppBskyFeedDefs.isPostView(item.subject)) {
const quotedPost = getEmbeddedPost(item.subject?.embed)
if (quotedPost && didOrHandleUriMatches(atUri, quotedPost)) {
yield embedViewRecordToPostView(quotedPost!)
}
}
}
}
@@ -307,7 +309,7 @@ export function* findAllPostsInQueryData(
export function* findAllProfilesInQueryData(
queryClient: QueryClient,
did: string,
): Generator<AppBskyActorDefs.ProfileView, void> {
): Generator<AppBskyActorDefs.ProfileViewBasic, void> {
const queryDatas = queryClient.getQueriesData<InfiniteData<FeedPage>>({
queryKey: [RQKEY_ROOT],
})
@@ -323,9 +325,11 @@ export function* findAllProfilesInQueryData(
) {
yield item.subject.author
}
const quotedPost = getEmbeddedPost(item.subject?.embed)
if (quotedPost?.author.did === did) {
yield quotedPost.author
if (AppBskyFeedDefs.isPostView(item.subject)) {
const quotedPost = getEmbeddedPost(item.subject?.embed)
if (quotedPost?.author.did === did) {
yield quotedPost.author
}
}
}
}
+2 -2
View File
@@ -255,8 +255,8 @@ function getSubjectUri(
return notif.uri
} else if (type === 'post-like' || type === 'repost') {
if (
AppBskyFeedRepost.isRecord(notif.record) ||
AppBskyFeedLike.isRecord(notif.record)
AppBskyFeedRepost.isValidRecord(notif.record) ||
AppBskyFeedLike.isValidRecord(notif.record)
) {
return typeof notif.record.subject?.uri === 'string'
? notif.record.subject?.uri
+1 -1
View File
@@ -543,7 +543,7 @@ export function* findAllPostsInQueryData(
export function* findAllProfilesInQueryData(
queryClient: QueryClient,
did: string,
): Generator<AppBskyActorDefs.ProfileView, undefined> {
): Generator<AppBskyActorDefs.ProfileViewBasic, undefined> {
const queryDatas = queryClient.getQueriesData<
InfiniteData<FeedPageUnselected>
>({
+1 -1
View File
@@ -70,7 +70,7 @@ export function usePostQuotesQuery(resolvedUri: string | undefined) {
export function* findAllProfilesInQueryData(
queryClient: QueryClient,
did: string,
): Generator<AppBskyActorDefs.ProfileView, void> {
): Generator<AppBskyActorDefs.ProfileViewBasic, void> {
const queryDatas = queryClient.getQueriesData<
InfiniteData<AppBskyFeedGetQuotes.OutputSchema>
>({
+6 -4
View File
@@ -329,8 +329,7 @@ function responseToThreadNodes(
): ThreadNode {
if (
AppBskyFeedDefs.isThreadViewPost(node) &&
AppBskyFeedPost.isRecord(node.post.record) &&
AppBskyFeedPost.validateRecord(node.post.record).success
AppBskyFeedPost.isValidRecord(node.post.record)
) {
const post = node.post
// These should normally be present. They're missing only for
@@ -360,7 +359,7 @@ function responseToThreadNodes(
depth,
isHighlightedPost: depth === 0,
hasMore:
direction === 'down' && !node.replies?.length && !!node.replyCount,
direction === 'down' && !node.replies?.length && !!post.replyCount,
isSelfThread: false, // populated `annotateSelfThread`
hasMoreSelfThread: false, // populated in `annotateSelfThread`
},
@@ -493,7 +492,10 @@ export function* findAllPostsInQueryData(
export function* findAllProfilesInQueryData(
queryClient: QueryClient,
did: string,
): Generator<AppBskyActorDefs.ProfileView, void> {
): Generator<
AppBskyActorDefs.ProfileView | AppBskyActorDefs.ProfileViewBasic,
void
> {
const queryDatas = queryClient.getQueriesData<PostThreadQueryData>({
queryKey: [RQKEY_ROOT],
})
+1 -1
View File
@@ -60,7 +60,7 @@ export async function getPostgateRecord({
}),
)
if (data.value && AppBskyFeedPostgate.isRecord(data.value)) {
if (data.value && AppBskyFeedPostgate.isValidRecord(data.value)) {
return data.value
} else {
return undefined
+8 -3
View File
@@ -5,6 +5,7 @@ import {
AppBskyFeedPostgate,
AtUri,
} from '@atproto/api'
import {$Typed} from '@atproto/api/dist/client/util'
export const POSTGATE_COLLECTION = 'app.bsky.feed.postgate'
@@ -45,8 +46,12 @@ export function mergePostgateRecords(
})
}
export function createEmbedViewDetachedRecord({uri}: {uri: string}) {
const record: AppBskyEmbedRecord.ViewDetached = {
export function createEmbedViewDetachedRecord({
uri,
}: {
uri: string
}): $Typed<AppBskyEmbedRecord.View> {
const record: $Typed<AppBskyEmbedRecord.ViewDetached> = {
$type: 'app.bsky.embed.record#viewDetached',
uri,
detached: true,
@@ -95,7 +100,7 @@ export function createMaybeDetachedQuoteEmbed({
export function createEmbedViewRecordFromPost(
post: AppBskyFeedDefs.PostView,
): AppBskyEmbedRecord.ViewRecord {
): $Typed<AppBskyEmbedRecord.ViewRecord> {
return {
$type: 'app.bsky.embed.record#viewRecord',
uri: post.uri,
+6 -6
View File
@@ -73,7 +73,7 @@ export function useProfileQuery({
placeholderData: () => {
if (!did) return
return queryClient.getQueryData<AppBskyActorDefs.ProfileViewBasic>(
return queryClient.getQueryData<AppBskyActorDefs.ProfileViewDetailed>(
profileBasicQueryKey(did),
)
},
@@ -113,7 +113,7 @@ export function usePrefetchProfileQuery() {
}
interface ProfileUpdateParams {
profile: AppBskyActorDefs.ProfileView
profile: AppBskyActorDefs.ProfileViewDetailed
updates:
| AppBskyActorProfile.Record
| ((existing: AppBskyActorProfile.Record) => AppBskyActorProfile.Record)
@@ -220,7 +220,7 @@ export function useProfileUpdateMutation() {
}
export function useProfileFollowMutationQueue(
profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>,
profile: Shadow<Omit<AppBskyActorDefs.ProfileViewDetailed, '$type'>>,
logContext: LogEvents['profile:follow']['logContext'] &
LogEvents['profile:follow']['logContext'],
) {
@@ -294,7 +294,7 @@ export function useProfileFollowMutationQueue(
function useProfileFollowMutation(
logContext: LogEvents['profile:follow']['logContext'],
profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>,
profile: Shadow<Omit<AppBskyActorDefs.ProfileViewDetailed, '$type'>>,
) {
const {currentAccount} = useSession()
const agent = useAgent()
@@ -334,7 +334,7 @@ function useProfileUnfollowMutation(
}
export function useProfileMuteMutationQueue(
profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>,
profile: Shadow<Omit<AppBskyActorDefs.ProfileViewDetailed, '$type'>>,
) {
const queryClient = useQueryClient()
const did = profile.did
@@ -409,7 +409,7 @@ function useProfileUnmuteMutation() {
}
export function useProfileBlockMutationQueue(
profile: Shadow<AppBskyActorDefs.ProfileViewBasic>,
profile: Shadow<Omit<AppBskyActorDefs.ProfileViewBasic, '$type'>>,
) {
const queryClient = useQueryClient()
const did = profile.did
+4 -1
View File
@@ -174,7 +174,10 @@ export function* findAllPostsInQueryData(
export function* findAllProfilesInQueryData(
queryClient: QueryClient,
did: string,
): Generator<AppBskyActorDefs.ProfileView, undefined> {
): Generator<
AppBskyActorDefs.ProfileView | AppBskyActorDefs.ProfileViewBasic,
undefined
> {
const queryDatas = queryClient.getQueriesData<
InfiniteData<AppBskyFeedSearchPosts.OutputSchema>
>({
+1
View File
@@ -19,6 +19,7 @@ export function useServiceConfigQuery() {
const {data} = await agent.api.app.bsky.unspecced.getConfig()
return {
checkEmailConfirmed: Boolean(data.checkEmailConfirmed),
// @ts-expect-error TODO migrate once updated
topicsEnabled: Boolean(data.topicsEnabled),
}
} catch (e) {
+5 -2
View File
@@ -131,7 +131,7 @@ export function useCreateStarterPackMutation({
return await agent.app.bsky.graph.starterpack.create(
{
repo: agent.session?.did,
repo: agent.session?.did!,
},
{
name,
@@ -366,7 +366,10 @@ export async function precacheStarterPack(
let starterPackView: AppBskyGraphDefs.StarterPackView | undefined
if (AppBskyGraphDefs.isStarterPackView(starterPack)) {
starterPackView = starterPack
} else if (AppBskyGraphDefs.isStarterPackViewBasic(starterPack)) {
} else if (
AppBskyGraphDefs.isStarterPackViewBasic(starterPack) &&
AppBskyGraphStarterpack.isValidRecord(starterPack.record)
) {
const listView: AppBskyGraphDefs.ListViewBasic = {
uri: starterPack.record.list,
// This will be populated once the data from server is fetched
+1 -1
View File
@@ -138,7 +138,7 @@ export async function getThreadgateRecord({
}),
)
if (data.value && AppBskyFeedThreadgate.isRecord(data.value)) {
if (data.value && AppBskyFeedThreadgate.isValidRecord(data.value)) {
return data.value
} else {
return null
+1 -1
View File
@@ -3,4 +3,4 @@ export type ThreadgateAllowUISetting =
| {type: 'nobody'}
| {type: 'mention'}
| {type: 'following'}
| {type: 'list'; list: unknown}
| {type: 'list'; list: string}
+5 -11
View File
@@ -6,9 +6,7 @@ export function threadgateViewToAllowUISetting(
threadgateView: AppBskyFeedDefs.ThreadgateView | undefined,
): ThreadgateAllowUISetting[] {
const threadgate =
threadgateView &&
AppBskyFeedThreadgate.isRecord(threadgateView.record) &&
AppBskyFeedThreadgate.validateRecord(threadgateView.record).success
threadgateView && AppBskyFeedThreadgate.isValidRecord(threadgateView.record)
? threadgateView.record
: undefined
return threadgateRecordToAllowUISetting(threadgate)
@@ -39,11 +37,11 @@ export function threadgateRecordToAllowUISetting(
const settings: ThreadgateAllowUISetting[] = threadgate.allow
.map(allow => {
let setting: ThreadgateAllowUISetting | undefined
if (allow.$type === 'app.bsky.feed.threadgate#mentionRule') {
if (AppBskyFeedThreadgate.isValidMentionRule(allow)) {
setting = {type: 'mention'}
} else if (allow.$type === 'app.bsky.feed.threadgate#followingRule') {
} else if (AppBskyFeedThreadgate.isValidFollowingRule(allow)) {
setting = {type: 'following'}
} else if (allow.$type === 'app.bsky.feed.threadgate#listRule') {
} else if (AppBskyFeedThreadgate.isValidListRule(allow)) {
setting = {type: 'list', list: allow.list}
}
return setting
@@ -67,11 +65,7 @@ export function threadgateAllowUISettingToAllowRecordValue(
return undefined
}
let allow: (
| AppBskyFeedThreadgate.MentionRule
| AppBskyFeedThreadgate.FollowingRule
| AppBskyFeedThreadgate.ListRule
)[] = []
let allow: Exclude<AppBskyFeedThreadgate.Record['allow'], undefined> = []
if (!threadgate.find(v => v.type === 'nobody')) {
for (const rule of threadgate) {
+2 -2
View File
@@ -44,7 +44,7 @@ export function didOrHandleUriMatches(
export function getEmbeddedPost(
v: unknown,
): AppBskyEmbedRecord.ViewRecord | undefined {
if (AppBskyEmbedRecord.isView(v)) {
if (AppBskyEmbedRecord.isValidView(v)) {
if (
AppBskyEmbedRecord.isViewRecord(v.record) &&
AppBskyFeedPost.isRecord(v.record.value)
@@ -52,7 +52,7 @@ export function getEmbeddedPost(
return v.record
}
}
if (AppBskyEmbedRecordWithMedia.isView(v)) {
if (AppBskyEmbedRecordWithMedia.isValidView(v)) {
if (
AppBskyEmbedRecord.isViewRecord(v.record.record) &&
AppBskyFeedPost.isRecord(v.record.record.value)
+1
View File
@@ -0,0 +1 @@
export * as profile from '#/types/atproto/profile'
+67
View File
@@ -0,0 +1,67 @@
import {AppBskyActorDefs} from '@atproto/api'
export {
/**
* Renamed to clarify source of this util, but directly aliases the original.
* {@link AppBskyActorDefs.isProfileViewBasic}
*/
isProfileViewBasic as isBasicView,
/**
* Renamed to clarify source of this util, but directly aliases the original.
* {@link AppBskyActorDefs.isProfileViewDetailed}
*/
isProfileViewDetailed as isDetailedView,
/**
* Renamed to clarify source of this util, but directly aliases the original.
* {@link AppBskyActorDefs.isProfileView}
*/
isProfileView as isView,
} from '@atproto/api/dist/client/types/app/bsky/actor/defs'
/**
* Matches any profile view exported by our SDK
*/
export type AnyProfileView =
| AppBskyActorDefs.ProfileViewBasic
| AppBskyActorDefs.ProfileView
| AppBskyActorDefs.ProfileViewDetailed
/**
* Maps any profile view type to `ProfileViewBasic`.
*/
export function anyToBasic(
view: AnyProfileView,
): AppBskyActorDefs.ProfileViewBasic {
return {
$type: 'app.bsky.actor.defs#profileViewBasic',
did: view.did,
handle: view.handle,
displayName: view.displayName,
avatar: view.avatar,
associated: view.associated,
viewer: view.viewer,
labels: view.labels,
createdAt: view.createdAt,
}
}
/**
* Maps `ProfileViewDetailed` to `ProfileView`.
*/
export function detailedToView(
view: AppBskyActorDefs.ProfileViewDetailed,
): AppBskyActorDefs.ProfileView {
return {
$type: 'app.bsky.actor.defs#profileView',
did: view.did,
handle: view.handle,
displayName: view.displayName,
avatar: view.avatar,
associated: view.associated,
viewer: view.viewer,
labels: view.labels,
createdAt: view.createdAt,
description: view.description,
indexedAt: view.indexedAt,
}
}
+4 -3
View File
@@ -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 atp from '#/types/atproto'
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: atp.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: atp.profile.AnyProfileView) => {
if (!isOwner) {
return null
}
@@ -71,7 +71,7 @@ const MAX_AUTHORS = 5
const EXPANDED_AUTHOR_EL_HEIGHT = 35
interface Author {
profile: AppBskyActorDefs.ProfileViewBasic
profile: AppBskyActorDefs.ProfileView
href: string
moderation: ModerationDecision
}
@@ -120,6 +120,11 @@ let NotificationFeedItem = ({
}
const onBeforePress = React.useCallback(() => {
/*
* Notification returns ProfileView, which has one additional field on top
* of `Basic`: `indexedAt`. Harmless for now, but should be fixed.
*/
// @ts-expect-error TODO
precacheProfile(queryClient, item.notification.author)
}, [queryClient, item.notification.author])
@@ -264,7 +269,7 @@ let NotificationFeedItem = ({
if (
item.notification.author.viewer?.following &&
AppBskyGraphFollow.isRecord(item.notification.record)
AppBskyGraphFollow.isValidRecord(item.notification.record)
) {
let followingTimestamp
try {
@@ -521,7 +526,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 +721,7 @@ function ExpandedAuthorsList({
function AdditionalPostText({post}: {post?: AppBskyFeedDefs.PostView}) {
const pal = usePalette('default')
if (post && AppBskyFeedPost.isRecord(post?.record)) {
if (post && AppBskyFeedPost.isValidRecord(post?.record)) {
const text = post.record.text
return (
+1 -1
View File
@@ -16,7 +16,7 @@ function renderItem({
item,
index,
}: {
item: ActorDefs.ProfileViewBasic
item: ActorDefs.ProfileView
index: number
}) {
return (
@@ -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',
+1 -1
View File
@@ -785,7 +785,7 @@ function BackdatedPostIndicator({post}: {post: AppBskyFeedDefs.PostView}) {
const control = Prompt.usePromptControl()
const indexedAt = new Date(post.indexedAt)
const createdAt = AppBskyFeedPost.isRecord(post.record)
const createdAt = AppBskyFeedPost.isValidRecord(post.record)
? new Date(post.record.createdAt)
: new Date(post.indexedAt)
+1 -4
View File
@@ -53,10 +53,7 @@ export function Post({
const moderationOpts = useModerationOpts()
const record = useMemo<AppBskyFeedPost.Record | undefined>(
() =>
AppBskyFeedPost.isRecord(post.record) &&
AppBskyFeedPost.validateRecord(post.record).success
? post.record
: undefined,
AppBskyFeedPost.isValidRecord(post.record) ? post.record : undefined,
[post],
)
const postShadowed = usePostShadow(post)
+2 -2
View File
@@ -232,7 +232,7 @@ 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 = AppBskyFeedThreadgate.isValidRecord(
rootPost.threadgate?.record,
)
? rootPost.threadgate.record
@@ -461,7 +461,7 @@ let PostContent = ({
})
const additionalPostAlerts: AppModerationCause[] = React.useMemo(() => {
const isPostHiddenByThreadgate = threadgateHiddenReplies.has(post.uri)
const rootPostUri = AppBskyFeedPost.isRecord(post.record)
const rootPostUri = AppBskyFeedPost.isValidRecord(post.record)
? post.record?.reply?.root?.uri || post.uri
: undefined
const isControlledByViewer =
+2 -2
View File
@@ -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 atp from '#/types/atproto'
import {Button, ButtonType} from '../util/forms/Button'
import * as Toast from '../util/Toast'
@@ -17,7 +17,7 @@ export function FollowButton({
}: {
unfollowedType?: ButtonType
followedType?: ButtonType
profile: Shadow<AppBskyActorDefs.ProfileViewBasic>
profile: Shadow<atp.profile.AnyProfileView>
labelStyle?: StyleProp<TextStyle>
logContext: 'ProfileCard' | 'StarterPackProfilesList'
}) {
+31 -24
View File
@@ -24,6 +24,7 @@ import {
shouldShowKnownFollowers,
} from '#/components/KnownFollowers'
import * as Pills from '#/components/Pills'
import * as atp from '#/types/atproto'
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: atp.profile.AnyProfileView
noModFilter?: boolean
noBg?: boolean
noBorder?: boolean
renderButton?: (
profile: Shadow<AppBskyActorDefs.ProfileViewBasic>,
profile: Shadow<atp.profile.AnyProfileView>,
) => React.ReactNode
onPress?: () => void
style?: StyleProp<ViewStyle>
@@ -60,7 +61,7 @@ export function ProfileCard({
const onBeforePress = React.useCallback(() => {
onPress?.()
precacheProfile(queryClient, profile)
precacheProfile(queryClient, atp.profile.anyToBasic(profile))
}, [onPress, profile, queryClient])
if (!moderationOpts) {
@@ -126,29 +127,35 @@ export function ProfileCard({
<View style={styles.layoutButton}>{renderButton(profile)}</View>
) : undefined}
</View>
{profile.description || knownFollowersVisible ? (
<View style={styles.details}>
{profile.description ? (
<Text emoji style={pal.text} numberOfLines={4}>
{profile.description as string}
</Text>
) : null}
{knownFollowersVisible ? (
<View
style={[
a.flex_row,
a.align_center,
a.gap_sm,
!!profile.description && a.mt_md,
]}>
<KnownFollowers
minimal
profile={profile}
moderationOpts={moderationOpts}
/>
{atp.profile.isView(profile) || atp.profile.isDetailedView(profile) ? (
<>
{profile.description || knownFollowersVisible ? (
<View style={styles.details}>
{profile.description ? (
<Text emoji style={pal.text} numberOfLines={4}>
{profile.description as string}
</Text>
) : null}
{knownFollowersVisible ? (
<View
style={[
a.flex_row,
a.align_center,
a.gap_sm,
!!profile.description && a.mt_md,
]}>
{atp.profile.isDetailedView(profile) && (
<KnownFollowers
minimal
profile={profile}
moderationOpts={moderationOpts}
/>
)}
</View>
) : null}
</View>
) : null}
</View>
</>
) : null}
</Link>
)
+1 -1
View File
@@ -17,7 +17,7 @@ function renderItem({
item,
index,
}: {
item: ActorDefs.ProfileViewBasic
item: ActorDefs.ProfileView
index: number
}) {
return (
+1 -1
View File
@@ -17,7 +17,7 @@ function renderItem({
item,
index,
}: {
item: ActorDefs.ProfileViewBasic
item: ActorDefs.ProfileView
index: number
}) {
return (
+1 -1
View File
@@ -54,7 +54,7 @@ interface EditableUserAvatarProps extends BaseUserAvatarProps {
interface PreviewableUserAvatarProps extends BaseUserAvatarProps {
moderation?: ModerationUI
profile: AppBskyActorDefs.ProfileViewBasic
profile: Omit<AppBskyActorDefs.ProfileViewBasic, '$type'>
disableHoverCard?: boolean
onBeforePress?: () => void
}
+4 -2
View File
@@ -171,8 +171,10 @@ 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)
const text = AppBskyFeedPost.isValidRecord(quote.record)
? quote.record.text
: ''
const facets = AppBskyFeedPost.isValidRecord(quote.record)
? quote.record.facets
: undefined
return text.trim()
+2
View File
@@ -133,6 +133,7 @@ export const DebugModScreen = ({}: NativeStackScreenProps<
})
mockedProfile.did = did
mockedProfile.avatar = 'https://bsky.social/about/images/favicon-32x32.png'
// @ts-ignore 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>
+12 -50
View File
@@ -58,10 +58,10 @@
resolved "https://registry.yarnpkg.com/@atproto-labs/simple-store/-/simple-store-0.1.1.tgz#e743a2722b5d8732166f0a72aca8bd10e9bff106"
integrity sha512-WKILW2b3QbAYKh+w5U2x6p5FqqLl0nAeLwGeDY+KjX01K4Dq3vQTR9b/qNp0jZm48CabPQVrqCv0PPU9LgRRRg==
"@atproto/api@^0.13.20":
version "0.13.20"
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.13.20.tgz#5140db303c3b0981958dfe6a5fa6d7d1cd7bb3cc"
integrity sha512-z/+CvG6BEttRHf856tKSe1AeUQNfrobRJldaHAthGmFk7O3wLZQyfcI9DUmBJQ9+4wAt0dZwvKWVGLZOV9eLHA==
"@atproto/api@0.14.0-next.1":
version "0.14.0-next.1"
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.14.0-next.1.tgz#26911122a0f1346cffdbdb716b05e2fc45fe058c"
integrity sha512-1MmJjCs00SEMiy2P4KEQ92ozkMG3L+kCiOQ90j/YicQCPiCuEdkgl3gYBRg6Hal2s1fncK7mZgvpk+btn3anzA==
dependencies:
"@atproto/common-web" "^0.3.1"
"@atproto/lexicon" "^0.4.4"
@@ -72,10 +72,10 @@
tlds "^1.234.0"
zod "^3.23.8"
"@atproto/api@^0.13.21":
version "0.13.21"
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.13.21.tgz#8ee27a07e5a024b5bf32408d9bd623dd598ad1cc"
integrity sha512-iOxSj2YS3Fx9IPz1NivKrSsdYPNbBgpnUH7+WhKYAMvDFDUe2PZe7taau8wsUjJAu/H3S0Mk2TDh5e/7tCRwHA==
"@atproto/api@^0.13.20":
version "0.13.20"
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.13.20.tgz#5140db303c3b0981958dfe6a5fa6d7d1cd7bb3cc"
integrity sha512-z/+CvG6BEttRHf856tKSe1AeUQNfrobRJldaHAthGmFk7O3wLZQyfcI9DUmBJQ9+4wAt0dZwvKWVGLZOV9eLHA==
dependencies:
"@atproto/common-web" "^0.3.1"
"@atproto/lexicon" "^0.4.4"
@@ -3261,7 +3261,7 @@
"@babel/parser" "^7.25.9"
"@babel/types" "^7.25.9"
"@babel/traverse--for-generate-function-map@npm:@babel/traverse@^7.25.3":
"@babel/traverse--for-generate-function-map@npm:@babel/traverse@^7.25.3", "@babel/traverse@^7.25.3", "@babel/traverse@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.9.tgz#a50f8fe49e7f69f53de5bea7e413cd35c5e13c84"
integrity sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==
@@ -3322,19 +3322,6 @@
debug "^4.3.1"
globals "^11.1.0"
"@babel/traverse@^7.25.3", "@babel/traverse@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.9.tgz#a50f8fe49e7f69f53de5bea7e413cd35c5e13c84"
integrity sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==
dependencies:
"@babel/code-frame" "^7.25.9"
"@babel/generator" "^7.25.9"
"@babel/parser" "^7.25.9"
"@babel/template" "^7.25.9"
"@babel/types" "^7.25.9"
debug "^4.3.1"
globals "^11.1.0"
"@babel/types@^7.0.0", "@babel/types@^7.20.0", "@babel/types@^7.20.7", "@babel/types@^7.22.10", "@babel/types@^7.22.5", "@babel/types@^7.3.3", "@babel/types@^7.4.4":
version "7.22.10"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.10.tgz#4a9e76446048f2c66982d1a989dd12b8a2d2dc03"
@@ -17509,16 +17496,7 @@ string-natural-compare@^3.0.1:
resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -17618,7 +17596,7 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -17632,13 +17610,6 @@ strip-ansi@^5.2.0:
dependencies:
ansi-regex "^4.1.0"
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^7.0.1:
version "7.1.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
@@ -18913,7 +18884,7 @@ wordwrap@^1.0.0:
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@@ -18931,15 +18902,6 @@ wrap-ansi@^6.2.0:
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrap-ansi@^8.0.1, wrap-ansi@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"