From 3375460a15bb1ec78996793778e3b1485dc5bb81 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 10:09:50 -0600 Subject: [PATCH 001/142] Bump SDK --- package.json | 2 +- yarn.lock | 62 ++++++++++------------------------------------------ 2 files changed, 13 insertions(+), 51 deletions(-) diff --git a/package.json b/package.json index 5a72b6c02a..ec4595eb4b 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/yarn.lock b/yarn.lock index cdc028fdc2..992ec8c621 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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" @@ -17502,16 +17489,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== @@ -17611,7 +17589,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== @@ -17625,13 +17603,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" @@ -18906,7 +18877,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== @@ -18924,15 +18895,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" From f7ee3a576a46d50642654bd7d00766c94ad62cc4 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 10:10:05 -0600 Subject: [PATCH 002/142] Use consistent type in profile query --- src/state/queries/profile.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/state/queries/profile.ts b/src/state/queries/profile.ts index fa5675e874..3835ff01e8 100644 --- a/src/state/queries/profile.ts +++ b/src/state/queries/profile.ts @@ -73,7 +73,7 @@ export function useProfileQuery({ placeholderData: () => { if (!did) return - return queryClient.getQueryData( + return queryClient.getQueryData( profileBasicQueryKey(did), ) }, From e47f7a13cb76ae6e36308a715f36c64ea7469dd5 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 10:24:00 -0600 Subject: [PATCH 003/142] Omit from constraint for profile shadow --- src/state/cache/profile-shadow.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/state/cache/profile-shadow.ts b/src/state/cache/profile-shadow.ts index afd3f19355..e55cd48538 100644 --- a/src/state/cache/profile-shadow.ts +++ b/src/state/cache/profile-shadow.ts @@ -35,7 +35,7 @@ const shadows: WeakMap< const emitter = new EventEmitter() export function useProfileShadow< - TProfileView extends AppBskyActorDefs.ProfileView, + TProfileView extends Omit, >(profile: TProfileView): Shadow { const [shadow, setShadow] = useState(() => shadows.get(profile)) const [prevPost, setPrevPost] = useState(profile) From 8579fa99d2510d913587813a26492aaaad8679dd Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 10:51:47 -0600 Subject: [PATCH 004/142] Replace isRecord with isValidRecord in QuoteEmbed --- src/view/com/util/post-embeds/QuoteEmbed.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/view/com/util/post-embeds/QuoteEmbed.tsx b/src/view/com/util/post-embeds/QuoteEmbed.tsx index cb549f7cda..91909ce950 100644 --- a/src/view/com/util/post-embeds/QuoteEmbed.tsx +++ b/src/view/com/util/post-embeds/QuoteEmbed.tsx @@ -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() From a9e6164d299a25b55d47f9d4f6e8b1e09e033a72 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 14:31:43 -0600 Subject: [PATCH 005/142] Omit type from constraint for old ProfileCard --- src/view/com/profile/ProfileCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/com/profile/ProfileCard.tsx b/src/view/com/profile/ProfileCard.tsx index eab8611dd4..f6e59fc69d 100644 --- a/src/view/com/profile/ProfileCard.tsx +++ b/src/view/com/profile/ProfileCard.tsx @@ -41,7 +41,7 @@ export function ProfileCard({ showKnownFollowers, }: { testID?: string - profile: AppBskyActorDefs.ProfileViewBasic + profile: Omit noModFilter?: boolean noBg?: boolean noBorder?: boolean From 1c956a23488710d1bdb0a154a85bd82abbf26579 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 14:54:25 -0600 Subject: [PATCH 006/142] Omit type from constraint in profile queries where appropriate --- src/state/queries/profile.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/state/queries/profile.ts b/src/state/queries/profile.ts index 3835ff01e8..dc028485d6 100644 --- a/src/state/queries/profile.ts +++ b/src/state/queries/profile.ts @@ -220,7 +220,7 @@ export function useProfileUpdateMutation() { } export function useProfileFollowMutationQueue( - profile: Shadow, + profile: Shadow>, 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, + profile: Shadow>, ) { const {currentAccount} = useSession() const agent = useAgent() @@ -334,7 +334,7 @@ function useProfileUnfollowMutation( } export function useProfileMuteMutationQueue( - profile: Shadow, + profile: Shadow>, ) { const queryClient = useQueryClient() const did = profile.did @@ -409,7 +409,7 @@ function useProfileUnmuteMutation() { } export function useProfileBlockMutationQueue( - profile: Shadow, + profile: Shadow>, ) { const queryClient = useQueryClient() const did = profile.did From ae48fdfac47e618b0b54990c1a6ee6270eb6967b Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 14:55:41 -0600 Subject: [PATCH 007/142] Use correct type for update profile mutation --- src/state/queries/profile.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/state/queries/profile.ts b/src/state/queries/profile.ts index dc028485d6..cb84037ebb 100644 --- a/src/state/queries/profile.ts +++ b/src/state/queries/profile.ts @@ -113,7 +113,7 @@ export function usePrefetchProfileQuery() { } interface ProfileUpdateParams { - profile: AppBskyActorDefs.ProfileView + profile: AppBskyActorDefs.ProfileViewDetailed updates: | AppBskyActorProfile.Record | ((existing: AppBskyActorProfile.Record) => AppBskyActorProfile.Record) From cb4add1efd8481b8e9870b520a3995d394a53869 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 15:03:03 -0600 Subject: [PATCH 008/142] Conslidate and fix check for isValidRecord in Post.tsx --- src/view/com/post/Post.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx index c87e361e16..bf256a4924 100644 --- a/src/view/com/post/Post.tsx +++ b/src/view/com/post/Post.tsx @@ -53,10 +53,7 @@ export function Post({ const moderationOpts = useModerationOpts() const record = useMemo( () => - AppBskyFeedPost.isRecord(post.record) && - AppBskyFeedPost.validateRecord(post.record).success - ? post.record - : undefined, + AppBskyFeedPost.isValidRecord(post.record) ? post.record : undefined, [post], ) const postShadowed = usePostShadow(post) From c98a97ed20225e41108cb9893f01fbde83b93c98 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 15:03:45 -0600 Subject: [PATCH 009/142] Replace isRecord with isValidRecord in PostThreadItem --- src/view/com/post-thread/PostThreadItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx index f04b9e225a..c68421b634 100644 --- a/src/view/com/post-thread/PostThreadItem.tsx +++ b/src/view/com/post-thread/PostThreadItem.tsx @@ -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) From 05eae07098b3c72c0caf4628f677d81b4b475d6b Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 15:04:27 -0600 Subject: [PATCH 010/142] Remove redundant cast in PostThreadFollowBtn --- src/view/com/post-thread/PostThreadFollowBtn.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/view/com/post-thread/PostThreadFollowBtn.tsx b/src/view/com/post-thread/PostThreadFollowBtn.tsx index 9dc93916a7..145e919f93 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 = - useProfileShadow(profileUnshadowed) + const profile = useProfileShadow(profileUnshadowed) const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue( profile, 'PostThreadItem', From f02f254de67367649276935a018a3d768b0a7d65 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 15:08:35 -0600 Subject: [PATCH 011/142] Ignore errors in DebugMod screen --- src/view/screens/DebugMod.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/view/screens/DebugMod.tsx b/src/view/screens/DebugMod.tsx index 4ff0a4b8bd..e515a9a0f1 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-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})} /> From 5c7e38eccf5442ae6435774da72ce7ec7d56196a Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 15:10:01 -0600 Subject: [PATCH 012/142] Use matching type in ProfileFollows screen --- src/view/com/profile/ProfileFollows.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/com/profile/ProfileFollows.tsx b/src/view/com/profile/ProfileFollows.tsx index 1cd65c74c0..d67a7261ab 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 ( From 3ea6ec14a0b9a0864447fc51abe956417d1e5b14 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 15:10:40 -0600 Subject: [PATCH 013/142] Use matching type in ProfileFollowers screen --- src/view/com/profile/ProfileFollowers.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/com/profile/ProfileFollowers.tsx b/src/view/com/profile/ProfileFollowers.tsx index 3c04769292..d6b7646566 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 ( From b0d195aec4be3b4844a70788171cc7a95b343bcb Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 15:11:29 -0600 Subject: [PATCH 014/142] Migrate to isValidRecord in PostFeedItem --- src/view/com/posts/PostFeedItem.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/view/com/posts/PostFeedItem.tsx b/src/view/com/posts/PostFeedItem.tsx index 4b18c470a6..8d6f41ac6b 100644 --- a/src/view/com/posts/PostFeedItem.tsx +++ b/src/view/com/posts/PostFeedItem.tsx @@ -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 = From aac65a8e0c9ab52b90fd9072d965ba2e2bb232be Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 15:12:46 -0600 Subject: [PATCH 015/142] Use matching type if PostRepostedBy --- src/view/com/post-thread/PostRepostedBy.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/com/post-thread/PostRepostedBy.tsx b/src/view/com/post-thread/PostRepostedBy.tsx index 2143bd9c27..c27e37f49c 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 ( From ac559171fc77465d9698ec65f0be25ce31cf4059 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 16:01:51 -0600 Subject: [PATCH 016/142] Omit type from constraint in avatar props --- src/view/com/util/UserAvatar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index dbd68f8ef5..2e4b4e6f0b 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -54,7 +54,7 @@ interface EditableUserAvatarProps extends BaseUserAvatarProps { interface PreviewableUserAvatarProps extends BaseUserAvatarProps { moderation?: ModerationUI - profile: AppBskyActorDefs.ProfileViewBasic + profile: Omit disableHoverCard?: boolean onBeforePress?: () => void } From b7da85d2df8a682d6ad60b82a0ec24a1a62c9a28 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 16:02:15 -0600 Subject: [PATCH 017/142] Use matching types in NotificationFeedItem --- src/view/com/notifications/NotificationFeedItem.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/view/com/notifications/NotificationFeedItem.tsx b/src/view/com/notifications/NotificationFeedItem.tsx index 1267ce0894..f43d617379 100644 --- a/src/view/com/notifications/NotificationFeedItem.tsx +++ b/src/view/com/notifications/NotificationFeedItem.tsx @@ -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 } @@ -521,7 +521,7 @@ function ExpandListPressable({ } } -function SayHelloBtn({profile}: {profile: AppBskyActorDefs.ProfileViewBasic}) { +function SayHelloBtn({profile}: {profile: AppBskyActorDefs.ProfileView}) { const {_} = useLingui() const agent = useAgent() const navigation = useNavigation() From a238666a968d4236925b8c9ddcdedd4f775d56c3 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 16:08:04 -0600 Subject: [PATCH 018/142] Todo --- src/view/com/notifications/NotificationFeedItem.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/view/com/notifications/NotificationFeedItem.tsx b/src/view/com/notifications/NotificationFeedItem.tsx index f43d617379..a8ac4019dc 100644 --- a/src/view/com/notifications/NotificationFeedItem.tsx +++ b/src/view/com/notifications/NotificationFeedItem.tsx @@ -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]) From 2c782d72ece35e4af59386c16e28b0d8aaea389c Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 16:12:55 -0600 Subject: [PATCH 019/142] Use isValidRecord in NotfyFeedItem --- src/view/com/notifications/NotificationFeedItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/com/notifications/NotificationFeedItem.tsx b/src/view/com/notifications/NotificationFeedItem.tsx index a8ac4019dc..15ec96816d 100644 --- a/src/view/com/notifications/NotificationFeedItem.tsx +++ b/src/view/com/notifications/NotificationFeedItem.tsx @@ -721,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 ( From 9182a6a0fc33226ad151706cdb937958583efc04 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 16:15:53 -0600 Subject: [PATCH 020/142] Improve MediaPreview types --- src/components/MediaPreview.tsx | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/components/MediaPreview.tsx b/src/components/MediaPreview.tsx index 9a05b54dff..0d5ef05fc8 100644 --- a/src/components/MediaPreview.tsx +++ b/src/components/MediaPreview.tsx @@ -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 }) { let media = AppBskyEmbedRecordWithMedia.isView(embed) ? embed.media : embed - if (AppBskyEmbedImages.isView(media)) { + if (AppBskyEmbedImages.isValidView(media)) { return ( {media.images.map(image => ( @@ -44,7 +40,7 @@ export function Embed({ ))} ) - } 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 ( From 37c5329e4f39709328cb954856ee3ab152318730 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 16:19:11 -0600 Subject: [PATCH 021/142] Migrate another isValidRecord in NotificationFeedItem --- src/view/com/notifications/NotificationFeedItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/com/notifications/NotificationFeedItem.tsx b/src/view/com/notifications/NotificationFeedItem.tsx index 15ec96816d..2a6ad135e4 100644 --- a/src/view/com/notifications/NotificationFeedItem.tsx +++ b/src/view/com/notifications/NotificationFeedItem.tsx @@ -269,7 +269,7 @@ let NotificationFeedItem = ({ if ( item.notification.author.viewer?.following && - AppBskyGraphFollow.isRecord(item.notification.record) + AppBskyGraphFollow.isValidRecord(item.notification.record) ) { let followingTimestamp try { From b0685612d0b47855c8fe1b7e63280315f60673ea Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 17:05:13 -0600 Subject: [PATCH 022/142] Migrate to isValidView in queries/util --- src/state/queries/util.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/state/queries/util.ts b/src/state/queries/util.ts index 887c1df0ac..9615c18fed 100644 --- a/src/state/queries/util.ts +++ b/src/state/queries/util.ts @@ -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) From 68626a51e723deae39cd93bc8219dbd3c71ca5a7 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 17:05:55 -0600 Subject: [PATCH 023/142] Migrate to isValidRecord in threadgate/util --- src/state/queries/threadgate/util.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/state/queries/threadgate/util.ts b/src/state/queries/threadgate/util.ts index 09ae0a0c1f..fdaa2671f1 100644 --- a/src/state/queries/threadgate/util.ts +++ b/src/state/queries/threadgate/util.ts @@ -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) From 1e8823a50700dadcf00d709bc673fc53bd5ade9d Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 17:21:51 -0600 Subject: [PATCH 024/142] Fix types in threadgates --- src/state/queries/threadgate/index.ts | 2 +- src/state/queries/threadgate/types.ts | 2 +- src/state/queries/threadgate/util.ts | 12 ++++-------- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/state/queries/threadgate/index.ts b/src/state/queries/threadgate/index.ts index 8aa9320814..87e6d6666c 100644 --- a/src/state/queries/threadgate/index.ts +++ b/src/state/queries/threadgate/index.ts @@ -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 diff --git a/src/state/queries/threadgate/types.ts b/src/state/queries/threadgate/types.ts index 0cbea311cb..ac215199d2 100644 --- a/src/state/queries/threadgate/types.ts +++ b/src/state/queries/threadgate/types.ts @@ -3,4 +3,4 @@ export type ThreadgateAllowUISetting = | {type: 'nobody'} | {type: 'mention'} | {type: 'following'} - | {type: 'list'; list: unknown} + | {type: 'list'; list: string} diff --git a/src/state/queries/threadgate/util.ts b/src/state/queries/threadgate/util.ts index fdaa2671f1..c4eda74f47 100644 --- a/src/state/queries/threadgate/util.ts +++ b/src/state/queries/threadgate/util.ts @@ -37,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 @@ -65,11 +65,7 @@ export function threadgateAllowUISettingToAllowRecordValue( return undefined } - let allow: ( - | AppBskyFeedThreadgate.MentionRule - | AppBskyFeedThreadgate.FollowingRule - | AppBskyFeedThreadgate.ListRule - )[] = [] + let allow: Exclude = [] if (!threadgate.find(v => v.type === 'nobody')) { for (const rule of threadgate) { From 876ce4af7f39dbcbb4c43b2818e038dc0498c6f0 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 17:28:07 -0600 Subject: [PATCH 025/142] Fix up types in starter-packs queries --- src/state/queries/starter-packs.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/state/queries/starter-packs.ts b/src/state/queries/starter-packs.ts index 4066f8f192..1edc56ab04 100644 --- a/src/state/queries/starter-packs.ts +++ b/src/state/queries/starter-packs.ts @@ -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 From a7b01111557a5822fbc715b6eae050e86cf29524 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 17:43:14 -0600 Subject: [PATCH 026/142] Todo --- src/state/queries/service-config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/state/queries/service-config.ts b/src/state/queries/service-config.ts index 9a9db78659..dce8b85e8a 100644 --- a/src/state/queries/service-config.ts +++ b/src/state/queries/service-config.ts @@ -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) { From 3b3a5e0e13a04e541ff6709fbf3ed923b2d06de0 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 17:43:38 -0600 Subject: [PATCH 027/142] Specify exact types in search-posts --- src/state/queries/search-posts.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/state/queries/search-posts.ts b/src/state/queries/search-posts.ts index 8a8a3fa52f..7ecf239ef8 100644 --- a/src/state/queries/search-posts.ts +++ b/src/state/queries/search-posts.ts @@ -174,7 +174,10 @@ export function* findAllPostsInQueryData( export function* findAllProfilesInQueryData( queryClient: QueryClient, did: string, -): Generator { +): Generator< + AppBskyActorDefs.ProfileView | AppBskyActorDefs.ProfileViewBasic, + undefined +> { const queryDatas = queryClient.getQueriesData< InfiniteData >({ From a5c1fd7554ab7ab6f96a59df92ae317bf0f3015f Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 17:49:34 -0600 Subject: [PATCH 028/142] Use internal type util to align types --- src/state/queries/postgate/util.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/state/queries/postgate/util.ts b/src/state/queries/postgate/util.ts index 96762d38cb..639d784ed3 100644 --- a/src/state/queries/postgate/util.ts +++ b/src/state/queries/postgate/util.ts @@ -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' @@ -95,7 +96,7 @@ export function createMaybeDetachedQuoteEmbed({ export function createEmbedViewRecordFromPost( post: AppBskyFeedDefs.PostView, -): AppBskyEmbedRecord.ViewRecord { +): $Typed { return { $type: 'app.bsky.embed.record#viewRecord', uri: post.uri, From 626cfc80eb395862b70bd17ac0beb24ed4a45af0 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 17:58:51 -0600 Subject: [PATCH 029/142] Ditto last --- src/state/queries/postgate/util.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/state/queries/postgate/util.ts b/src/state/queries/postgate/util.ts index 639d784ed3..d7c0d1b7d7 100644 --- a/src/state/queries/postgate/util.ts +++ b/src/state/queries/postgate/util.ts @@ -46,8 +46,12 @@ export function mergePostgateRecords( }) } -export function createEmbedViewDetachedRecord({uri}: {uri: string}) { - const record: AppBskyEmbedRecord.ViewDetached = { +export function createEmbedViewDetachedRecord({ + uri, +}: { + uri: string +}): $Typed { + const record: $Typed = { $type: 'app.bsky.embed.record#viewDetached', uri, detached: true, From f2a8c5c9518ad5ec460cd40c5a8c3aade0d4b2b0 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 18:02:46 -0600 Subject: [PATCH 030/142] Migrate postgate/index --- src/state/queries/postgate/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/state/queries/postgate/index.ts b/src/state/queries/postgate/index.ts index 149b9cbe93..84bc2d765d 100644 --- a/src/state/queries/postgate/index.ts +++ b/src/state/queries/postgate/index.ts @@ -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 From 46bf56e3e34cb18a1a11657fb446a8aa52c2e492 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 2 Jan 2025 18:12:52 -0600 Subject: [PATCH 031/142] Specify exact types in post-thread --- src/state/queries/post-thread.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/state/queries/post-thread.ts b/src/state/queries/post-thread.ts index 2ebaf4f7dc..1dd2a3c3db 100644 --- a/src/state/queries/post-thread.ts +++ b/src/state/queries/post-thread.ts @@ -493,7 +493,10 @@ export function* findAllPostsInQueryData( export function* findAllProfilesInQueryData( queryClient: QueryClient, did: string, -): Generator { +): Generator< + AppBskyActorDefs.ProfileView | AppBskyActorDefs.ProfileViewBasic, + void +> { const queryDatas = queryClient.getQueriesData({ queryKey: [RQKEY_ROOT], }) From 0531cc7d8980834f8729743db13fb230bc1e7a49 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 3 Jan 2025 09:23:54 -0600 Subject: [PATCH 032/142] Use correct type in post-quotes --- src/state/queries/post-quotes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/state/queries/post-quotes.ts b/src/state/queries/post-quotes.ts index be51eaab0a..af9699d2b8 100644 --- a/src/state/queries/post-quotes.ts +++ b/src/state/queries/post-quotes.ts @@ -70,7 +70,7 @@ export function usePostQuotesQuery(resolvedUri: string | undefined) { export function* findAllProfilesInQueryData( queryClient: QueryClient, did: string, -): Generator { +): Generator { const queryDatas = queryClient.getQueriesData< InfiniteData >({ From 16addd86588686cc5f78486e2f2aa46ec1b8f22c Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 3 Jan 2025 09:25:53 -0600 Subject: [PATCH 033/142] FIX potential bug in post-thread --- src/state/queries/post-thread.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/state/queries/post-thread.ts b/src/state/queries/post-thread.ts index 1dd2a3c3db..dd4c494c1a 100644 --- a/src/state/queries/post-thread.ts +++ b/src/state/queries/post-thread.ts @@ -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` }, From aa18e81a1d5db845b27e8f475e04928dd09a69d7 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 3 Jan 2025 09:26:45 -0600 Subject: [PATCH 034/142] Use correct type in post-feed --- src/state/queries/post-feed.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/state/queries/post-feed.ts b/src/state/queries/post-feed.ts index 2eb604627e..53f2d318f5 100644 --- a/src/state/queries/post-feed.ts +++ b/src/state/queries/post-feed.ts @@ -543,7 +543,7 @@ export function* findAllPostsInQueryData( export function* findAllProfilesInQueryData( queryClient: QueryClient, did: string, -): Generator { +): Generator { const queryDatas = queryClient.getQueriesData< InfiniteData >({ From beb62f496190a72d23fbf62c99bdd47163112789 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 3 Jan 2025 09:29:50 -0600 Subject: [PATCH 035/142] Add correct type guards to notifications/feed --- src/state/queries/notifications/feed.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/state/queries/notifications/feed.ts b/src/state/queries/notifications/feed.ts index 72100a6245..3969941104 100644 --- a/src/state/queries/notifications/feed.ts +++ b/src/state/queries/notifications/feed.ts @@ -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 { +): Generator { const queryDatas = queryClient.getQueriesData>({ 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 + } } } } From 4053b724160c0016e5c2c9e6fdff8e1378f9e438 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 3 Jan 2025 09:48:22 -0600 Subject: [PATCH 036/142] Migrate a guard in notifications/util --- src/state/queries/notifications/util.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/state/queries/notifications/util.ts b/src/state/queries/notifications/util.ts index 0d72e9e929..b41c50d586 100644 --- a/src/state/queries/notifications/util.ts +++ b/src/state/queries/notifications/util.ts @@ -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 From 6c7cfc00470e71666efc38bb25793d9083034b51 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 3 Jan 2025 09:58:30 -0600 Subject: [PATCH 037/142] Migrate guard in Wizard/State --- src/screens/StarterPack/Wizard/State.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/screens/StarterPack/Wizard/State.tsx b/src/screens/StarterPack/Wizard/State.tsx index f65933fbb0..b6da56065b 100644 --- a/src/screens/StarterPack/Wizard/State.tsx +++ b/src/screens/StarterPack/Wizard/State.tsx @@ -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', From e23ce16ff2b6699499ae1777fd017f52cadd7038 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Mon, 6 Jan 2025 14:17:49 -0600 Subject: [PATCH 038/142] [@next] Profile handling, migrate `ProfileCard` (#7347) * Introduce new utils for profiles, migrate old ProfileCard * Rename, reorg --- src/types/atproto/index.ts | 1 + src/types/atproto/profile.ts | 67 +++++++++++++++++++++++++++ src/view/com/lists/ListMembers.tsx | 7 +-- src/view/com/profile/FollowButton.tsx | 4 +- src/view/com/profile/ProfileCard.tsx | 55 ++++++++++++---------- 5 files changed, 105 insertions(+), 29 deletions(-) create mode 100644 src/types/atproto/index.ts create mode 100644 src/types/atproto/profile.ts diff --git a/src/types/atproto/index.ts b/src/types/atproto/index.ts new file mode 100644 index 0000000000..58e2a5eb23 --- /dev/null +++ b/src/types/atproto/index.ts @@ -0,0 +1 @@ +export * as profile from '#/types/atproto/profile' diff --git a/src/types/atproto/profile.ts b/src/types/atproto/profile.ts new file mode 100644 index 0000000000..884f10295d --- /dev/null +++ b/src/types/atproto/profile.ts @@ -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, + } +} diff --git a/src/view/com/lists/ListMembers.tsx b/src/view/com/lists/ListMembers.tsx index 0caae67011..c8ecfc057a 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 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 } diff --git a/src/view/com/profile/FollowButton.tsx b/src/view/com/profile/FollowButton.tsx index c2d76316e6..6446b7b878 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 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 + profile: Shadow labelStyle?: StyleProp logContext: 'ProfileCard' | 'StarterPackProfilesList' }) { diff --git a/src/view/com/profile/ProfileCard.tsx b/src/view/com/profile/ProfileCard.tsx index f6e59fc69d..8a258498fb 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 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: Omit + profile: atp.profile.AnyProfileView noModFilter?: boolean noBg?: boolean noBorder?: boolean renderButton?: ( - profile: Shadow, + profile: Shadow, ) => React.ReactNode onPress?: () => void style?: StyleProp @@ -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({ {renderButton(profile)} ) : undefined} - {profile.description || knownFollowersVisible ? ( - - {profile.description ? ( - - {profile.description as string} - - ) : null} - {knownFollowersVisible ? ( - - + {atp.profile.isView(profile) || atp.profile.isDetailedView(profile) ? ( + <> + {profile.description || knownFollowersVisible ? ( + + {profile.description ? ( + + {profile.description as string} + + ) : null} + {knownFollowersVisible ? ( + + {atp.profile.isDetailedView(profile) && ( + + )} + + ) : null} ) : null} - + ) : null} ) From 55055c1cd0bac05dc6fcd04ef11901da2a5096f9 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Mon, 6 Jan 2025 15:44:04 -0600 Subject: [PATCH 039/142] Add parseEmbed utils --- src/components/MediaPreview.tsx | 31 ++++---- src/types/atproto/post.ts | 136 ++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 17 deletions(-) create mode 100644 src/types/atproto/post.ts diff --git a/src/components/MediaPreview.tsx b/src/components/MediaPreview.tsx index 0d5ef05fc8..9d9c755456 100644 --- a/src/components/MediaPreview.tsx +++ b/src/components/MediaPreview.tsx @@ -1,13 +1,7 @@ import React from 'react' import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native' import {Image} from 'expo-image' -import { - AppBskyEmbedExternal, - AppBskyEmbedImages, - AppBskyEmbedRecordWithMedia, - AppBskyEmbedVideo, - AppBskyFeedDefs, -} from '@atproto/api' +import {AppBskyFeedDefs} from '@atproto/api' import {Trans} from '@lingui/macro' import {parseTenorGif} from '#/lib/strings/embed-player' @@ -15,6 +9,7 @@ import {atoms as a, useTheme} from '#/alf' import {MediaInsetBorder} from '#/components/MediaInsetBorder' import {Text} from '#/components/Typography' import {PlayButtonIcon} from '#/components/video/PlayButtonIcon' +import {parseEmbed} from '#/types/atproto/post' /** * Streamlined MediaPreview component which just handles images, gifs, and videos @@ -23,15 +18,17 @@ export function Embed({ embed, style, }: { - embed?: AppBskyFeedDefs.PostView['embed'] + embed: AppBskyFeedDefs.PostView['embed'] style?: StyleProp }) { - let media = AppBskyEmbedRecordWithMedia.isView(embed) ? embed.media : embed + const e = parseEmbed(embed) - if (AppBskyEmbedImages.isValidView(media)) { + if (!e) return null + + if (e.type === 'images') { return ( - {media.images.map(image => ( + {e.view.images.map(image => ( ) - } else if (AppBskyEmbedExternal.isValidView(media) && media.external.thumb) { + } else if (e.type === 'link' && e.view.external.thumb) { let url: URL | undefined try { - url = new URL(media.external.uri) + url = new URL(e.view.external.uri) } catch {} if (url) { const {success} = parseTenorGif(url) @@ -51,17 +48,17 @@ export function Embed({ return ( ) } } - } else if (AppBskyEmbedVideo.isValidView(media)) { + } else if (e.type === 'video') { return ( - + ) } diff --git a/src/types/atproto/post.ts b/src/types/atproto/post.ts new file mode 100644 index 0000000000..ffd6eb47d2 --- /dev/null +++ b/src/types/atproto/post.ts @@ -0,0 +1,136 @@ +import { + AppBskyEmbedExternal, + AppBskyEmbedImages, + AppBskyEmbedRecord, + AppBskyEmbedRecordWithMedia, + AppBskyEmbedVideo, + AppBskyFeedDefs, + AppBskyGraphDefs, + AppBskyLabelerDefs, +} from '@atproto/api' + +export type View = + | { + type: 'post' + view: AppBskyEmbedRecord.ViewRecord + } + | { + type: 'post_not_found' + view: AppBskyEmbedRecord.ViewNotFound + } + | { + type: 'post_blocked' + view: AppBskyEmbedRecord.ViewBlocked + } + | { + type: 'post_detached' + view: AppBskyEmbedRecord.ViewDetached + } + | { + type: 'feed' + view: AppBskyFeedDefs.GeneratorView + } + | { + type: 'list' + view: AppBskyGraphDefs.ListView + } + | { + type: 'labeler' + view: AppBskyLabelerDefs.LabelerView + } + | { + type: 'starter_pack' + view: AppBskyGraphDefs.StarterPackViewBasic + } + | { + type: 'images' + view: AppBskyEmbedImages.View + } + | { + type: 'link' + view: AppBskyEmbedExternal.View + } + | { + type: 'video' + view: AppBskyEmbedVideo.View + } + | { + type: 'post_with_media' + view: View | undefined + media: View | undefined + } + +export function parseEmbedView( + view: AppBskyEmbedRecord.View, +): View | undefined { + if (AppBskyEmbedRecord.isViewRecord(view.record)) { + return { + type: 'post', + view: view.record, + } + } else if (AppBskyEmbedRecord.isViewNotFound(view.record)) { + return { + type: 'post_not_found', + view: view.record, + } + } else if (AppBskyEmbedRecord.isViewBlocked(view.record)) { + return { + type: 'post_blocked', + view: view.record, + } + } else if (AppBskyEmbedRecord.isViewDetached(view.record)) { + return { + type: 'post_detached', + view: view.record, + } + } else if (AppBskyFeedDefs.isGeneratorView(view.record)) { + return { + type: 'feed', + view: view.record, + } + } else if (AppBskyGraphDefs.isListView(view.record)) { + return { + type: 'list', + view: view.record, + } + } else if (AppBskyLabelerDefs.isLabelerView(view.record)) { + return { + type: 'labeler', + view: view.record, + } + } else if (AppBskyGraphDefs.isStarterPackViewBasic(view.record)) { + return { + type: 'starter_pack', + view: view.record, + } + } +} + +export function parseEmbed( + embed: AppBskyFeedDefs.PostView['embed'], +): View | undefined { + if (AppBskyEmbedImages.isView(embed)) { + return { + type: 'images', + view: embed, + } + } else if (AppBskyEmbedExternal.isView(embed)) { + return { + type: 'link', + view: embed, + } + } else if (AppBskyEmbedVideo.isView(embed)) { + return { + type: 'video', + view: embed, + } + } else if (AppBskyEmbedRecord.isView(embed)) { + return parseEmbedView(embed) + } else if (AppBskyEmbedRecordWithMedia.isView(embed)) { + return { + type: 'post_with_media', + view: parseEmbedView(embed.record), + media: parseEmbed(embed.media), + } + } +} From 9e7d34a730aab5519a71bb8cc2b81ca6c3143599 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Mon, 6 Jan 2025 16:01:07 -0600 Subject: [PATCH 040/142] Expand AnyProfileView to include chat profile view, update post shadow to reflect this --- src/state/cache/profile-shadow.ts | 11 ++++++----- src/types/atproto/profile.ts | 8 ++++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/state/cache/profile-shadow.ts b/src/state/cache/profile-shadow.ts index e55cd48538..b085ee922a 100644 --- a/src/state/cache/profile-shadow.ts +++ b/src/state/cache/profile-shadow.ts @@ -1,9 +1,9 @@ import {useEffect, useMemo, useState} from 'react' -import {AppBskyActorDefs} from '@atproto/api' import {QueryClient} from '@tanstack/react-query' import EventEmitter from 'eventemitter3' import {batchedUpdates} from '#/lib/batchedUpdates' +import * as atp from '#/types/atproto' import {findAllProfilesInQueryData as findAllProfilesInActorSearchQueryData} from '../queries/actor-search' import {findAllProfilesInQueryData as findAllProfilesInKnownFollowersQueryData} from '../queries/known-followers' import {findAllProfilesInQueryData as findAllProfilesInListMembersQueryData} from '../queries/list-members' @@ -20,6 +20,7 @@ import {findAllProfilesInQueryData as findAllProfilesInProfileFollowersQueryData import {findAllProfilesInQueryData as findAllProfilesInProfileFollowsQueryData} from '../queries/profile-follows' import {findAllProfilesInQueryData as findAllProfilesInSuggestedFollowsQueryData} from '../queries/suggested-follows' import {castAsShadow, Shadow} from './types' + export type {Shadow} from './types' export interface ProfileShadow { @@ -29,13 +30,13 @@ export interface ProfileShadow { } const shadows: WeakMap< - AppBskyActorDefs.ProfileView, + atp.profile.AnyProfileView, Partial > = new WeakMap() const emitter = new EventEmitter() export function useProfileShadow< - TProfileView extends Omit, + TProfileView extends atp.profile.AnyProfileView, >(profile: TProfileView): Shadow { const [shadow, setShadow] = useState(() => shadows.get(profile)) const [prevPost, setPrevPost] = useState(profile) @@ -77,7 +78,7 @@ export function updateProfileShadow( }) } -function mergeShadow( +function mergeShadow( profile: TProfileView, shadow: Partial, ): Shadow { @@ -99,7 +100,7 @@ function mergeShadow( function* findProfilesInCache( queryClient: QueryClient, did: string, -): Generator { +): Generator { yield* findAllProfilesInListMembersQueryData(queryClient, did) yield* findAllProfilesInMyBlockedAccountsQueryData(queryClient, did) yield* findAllProfilesInMyMutedAccountsQueryData(queryClient, did) diff --git a/src/types/atproto/profile.ts b/src/types/atproto/profile.ts index 884f10295d..fd3a0c0816 100644 --- a/src/types/atproto/profile.ts +++ b/src/types/atproto/profile.ts @@ -1,4 +1,4 @@ -import {AppBskyActorDefs} from '@atproto/api' +import {AppBskyActorDefs, ChatBskyActorDefs} from '@atproto/api' export { /** @@ -25,6 +25,7 @@ export type AnyProfileView = | AppBskyActorDefs.ProfileViewBasic | AppBskyActorDefs.ProfileView | AppBskyActorDefs.ProfileViewDetailed + | ChatBskyActorDefs.ProfileViewBasic /** * Maps any profile view type to `ProfileViewBasic`. @@ -41,7 +42,10 @@ export function anyToBasic( associated: view.associated, viewer: view.viewer, labels: view.labels, - createdAt: view.createdAt, + // @ts-expect-error `createdAt` doesn't exist on chat view + createdAt: ChatBskyActorDefs.isProfileViewBasic(view) + ? undefined + : view.createdAt, } } From a4e4e12d570d8e6c1ae468c81cacd689e809be3e Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Mon, 6 Jan 2025 16:05:03 -0600 Subject: [PATCH 041/142] Cast for perf reasons --- src/state/queries/notifications/util.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/state/queries/notifications/util.ts b/src/state/queries/notifications/util.ts index b41c50d586..e5f957ec2b 100644 --- a/src/state/queries/notifications/util.ts +++ b/src/state/queries/notifications/util.ts @@ -255,11 +255,14 @@ function getSubjectUri( return notif.uri } else if (type === 'post-like' || type === 'repost') { if ( - AppBskyFeedRepost.isValidRecord(notif.record) || - AppBskyFeedLike.isValidRecord(notif.record) + AppBskyFeedRepost.isRecord(notif.record) || + AppBskyFeedLike.isRecord(notif.record) ) { - return typeof notif.record.subject?.uri === 'string' - ? notif.record.subject?.uri + const record = notif.record as + | AppBskyFeedRepost.Record + | AppBskyFeedLike.Record + return typeof record.subject?.uri === 'string' + ? record.subject?.uri : undefined } } else if (type === 'feedgen-like') { From e1a60bfa3c828b3266f2271be4909d4a58c8e736 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Mon, 6 Jan 2025 17:25:22 -0600 Subject: [PATCH 042/142] Tighten up types now that we have AnyProfileView --- src/state/queries/post-thread.ts | 5 +---- src/state/queries/search-posts.ts | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/state/queries/post-thread.ts b/src/state/queries/post-thread.ts index dd4c494c1a..5427268420 100644 --- a/src/state/queries/post-thread.ts +++ b/src/state/queries/post-thread.ts @@ -492,10 +492,7 @@ export function* findAllPostsInQueryData( export function* findAllProfilesInQueryData( queryClient: QueryClient, did: string, -): Generator< - AppBskyActorDefs.ProfileView | AppBskyActorDefs.ProfileViewBasic, - void -> { +): Generator { const queryDatas = queryClient.getQueriesData({ queryKey: [RQKEY_ROOT], }) diff --git a/src/state/queries/search-posts.ts b/src/state/queries/search-posts.ts index 7ecf239ef8..d0bfd55df6 100644 --- a/src/state/queries/search-posts.ts +++ b/src/state/queries/search-posts.ts @@ -174,10 +174,7 @@ export function* findAllPostsInQueryData( export function* findAllProfilesInQueryData( queryClient: QueryClient, did: string, -): Generator< - AppBskyActorDefs.ProfileView | AppBskyActorDefs.ProfileViewBasic, - undefined -> { +): Generator { const queryDatas = queryClient.getQueriesData< InfiniteData >({ From e4b6972c051fbb69c4221b34c54ad4b02f979654 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Mon, 6 Jan 2025 17:40:07 -0600 Subject: [PATCH 043/142] Add fastIsType util --- src/state/queries/notifications/util.ts | 18 +++++++++++------- src/state/queries/post-thread.ts | 6 +++++- src/types/atproto/index.ts | 23 +++++++++++++++++++++++ 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/state/queries/notifications/util.ts b/src/state/queries/notifications/util.ts index e5f957ec2b..0ffa7302dc 100644 --- a/src/state/queries/notifications/util.ts +++ b/src/state/queries/notifications/util.ts @@ -14,6 +14,7 @@ import {QueryClient} from '@tanstack/react-query' import chunk from 'lodash.chunk' import {labelIsHideableOffense} from '#/lib/moderation' +import * as atp from '#/types/atproto' import {precacheProfile} from '../profile' import {FeedNotification, FeedPage, NotificationType} from './types' @@ -255,14 +256,17 @@ function getSubjectUri( return notif.uri } else if (type === 'post-like' || type === 'repost') { if ( - AppBskyFeedRepost.isRecord(notif.record) || - AppBskyFeedLike.isRecord(notif.record) + atp.fastIsType( + notif.record, + AppBskyFeedRepost.isRecord, + ) || + atp.fastIsType( + notif.record, + AppBskyFeedLike.isRecord, + ) ) { - const record = notif.record as - | AppBskyFeedRepost.Record - | AppBskyFeedLike.Record - return typeof record.subject?.uri === 'string' - ? record.subject?.uri + return typeof notif.record.subject?.uri === 'string' + ? notif.record.subject?.uri : undefined } } else if (type === 'feedgen-like') { diff --git a/src/state/queries/post-thread.ts b/src/state/queries/post-thread.ts index 5427268420..beb50752d0 100644 --- a/src/state/queries/post-thread.ts +++ b/src/state/queries/post-thread.ts @@ -18,6 +18,7 @@ import { findAllProfilesInQueryData as findAllProfilesInSearchQueryData, } from '#/state/queries/search-posts' import {useAgent} from '#/state/session' +import * as atp from '#/types/atproto' import { findAllPostsInQueryData as findAllPostsInNotifsQueryData, findAllProfilesInQueryData as findAllProfilesInNotifsQueryData, @@ -329,7 +330,10 @@ function responseToThreadNodes( ): ThreadNode { if ( AppBskyFeedDefs.isThreadViewPost(node) && - AppBskyFeedPost.isValidRecord(node.post.record) + atp.fastIsType( + node.post.record, + AppBskyFeedPost.isRecord, + ) ) { const post = node.post // These should normally be present. They're missing only for diff --git a/src/types/atproto/index.ts b/src/types/atproto/index.ts index 58e2a5eb23..0f17653cc7 100644 --- a/src/types/atproto/index.ts +++ b/src/types/atproto/index.ts @@ -1 +1,24 @@ export * as profile from '#/types/atproto/profile' + +/** + * Use sparingly, and only when you know it's safe to do so. + * + * Our SDK's `is*` identity utils do not assert the type of the entire object, + * and although the `isValid*` utils do, they also fully validate the object + * shape, which has a performance cost. This util allows us to prescribe the + * type we expect, while only checking the `$type` value of the record. + * + * Usage: + * ```ts + * import * as atp from '#/types/atproto' + * + * if (atp.fastIsType(node.post.record, AppBskyFeedPost.isRecord)) { + * } + * ``` + */ +export function fastIsType( + record: unknown, + identity: (v: V) => boolean, +): record is R { + return identity(record) +} From f58dc57aacaa73aaefd1de623d7b7c2152773a44 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Mon, 6 Jan 2025 18:12:07 -0600 Subject: [PATCH 044/142] Use `assertDid` Co-authored-by: Matthieu Sieben --- src/state/queries/starter-packs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/state/queries/starter-packs.ts b/src/state/queries/starter-packs.ts index 1edc56ab04..85d2fc8254 100644 --- a/src/state/queries/starter-packs.ts +++ b/src/state/queries/starter-packs.ts @@ -131,7 +131,7 @@ export function useCreateStarterPackMutation({ return await agent.app.bsky.graph.starterpack.create( { - repo: agent.session?.did!, + repo: agent.assertDid, }, { name, From 4e9388a76d84c641a852191db6a77e22509d8be1 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Mon, 6 Jan 2025 18:09:53 -0600 Subject: [PATCH 045/142] Use util types --- src/state/queries/profile.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/state/queries/profile.ts b/src/state/queries/profile.ts index cb84037ebb..42dddbb975 100644 --- a/src/state/queries/profile.ts +++ b/src/state/queries/profile.ts @@ -24,6 +24,7 @@ import {Shadow} from '#/state/cache/types' import {STALE} from '#/state/queries' import {resetProfilePostsQueries} from '#/state/queries/post-feed' import * as userActionHistory from '#/state/userActionHistory' +import * as atp from '#/types/atproto' import {updateProfileShadow} from '../cache/profile-shadow' import {useAgent, useSession} from '../session' import { @@ -220,7 +221,7 @@ export function useProfileUpdateMutation() { } export function useProfileFollowMutationQueue( - profile: Shadow>, + profile: Shadow, logContext: LogEvents['profile:follow']['logContext'] & LogEvents['profile:follow']['logContext'], ) { @@ -294,7 +295,7 @@ export function useProfileFollowMutationQueue( function useProfileFollowMutation( logContext: LogEvents['profile:follow']['logContext'], - profile: Shadow>, + profile: Shadow, ) { const {currentAccount} = useSession() const agent = useAgent() @@ -313,7 +314,8 @@ function useProfileFollowMutation( didBecomeMutual: profile.viewer ? Boolean(profile.viewer.followedBy) : undefined, - followeeClout: toClout(profile.followersCount), + // @ts-expect-error — this is optional + followeeClout: toClout(profile?.followersCount), followerClout: toClout(ownProfile?.followersCount), }) return await agent.follow(did) @@ -334,7 +336,7 @@ function useProfileUnfollowMutation( } export function useProfileMuteMutationQueue( - profile: Shadow>, + profile: Shadow, ) { const queryClient = useQueryClient() const did = profile.did @@ -409,7 +411,7 @@ function useProfileUnmuteMutation() { } export function useProfileBlockMutationQueue( - profile: Shadow>, + profile: Shadow, ) { const queryClient = useQueryClient() const did = profile.did From b100d185b155532e9b9e4d9ca27b8bebfad24f93 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Mon, 6 Jan 2025 18:20:53 -0600 Subject: [PATCH 046/142] Comment --- src/state/queries/threadgate/util.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/state/queries/threadgate/util.ts b/src/state/queries/threadgate/util.ts index c4eda74f47..75c1bdef1a 100644 --- a/src/state/queries/threadgate/util.ts +++ b/src/state/queries/threadgate/util.ts @@ -5,6 +5,7 @@ import {ThreadgateAllowUISetting} from '#/state/queries/threadgate/types' export function threadgateViewToAllowUISetting( threadgateView: AppBskyFeedDefs.ThreadgateView | undefined, ): ThreadgateAllowUISetting[] { + // Validate the record for clarity, since backwards compat code is a little confusing const threadgate = threadgateView && AppBskyFeedThreadgate.isValidRecord(threadgateView.record) ? threadgateView.record @@ -37,11 +38,11 @@ export function threadgateRecordToAllowUISetting( const settings: ThreadgateAllowUISetting[] = threadgate.allow .map(allow => { let setting: ThreadgateAllowUISetting | undefined - if (AppBskyFeedThreadgate.isValidMentionRule(allow)) { + if (AppBskyFeedThreadgate.isMentionRule(allow)) { setting = {type: 'mention'} - } else if (AppBskyFeedThreadgate.isValidFollowingRule(allow)) { + } else if (AppBskyFeedThreadgate.isFollowingRule(allow)) { setting = {type: 'following'} - } else if (AppBskyFeedThreadgate.isValidListRule(allow)) { + } else if (AppBskyFeedThreadgate.isListRule(allow)) { setting = {type: 'list', list: allow.list} } return setting From 09cb5aa53bd001e36dc4659ea02afd5efc9cfe5b Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Mon, 6 Jan 2025 18:23:41 -0600 Subject: [PATCH 047/142] Use fastIsType where no validation was happening before --- src/state/queries/util.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/state/queries/util.ts b/src/state/queries/util.ts index 9615c18fed..081cb82ecc 100644 --- a/src/state/queries/util.ts +++ b/src/state/queries/util.ts @@ -8,6 +8,8 @@ import { } from '@atproto/api' import {InfiniteData, QueryClient, QueryKey} from '@tanstack/react-query' +import * as atp from '#/types/atproto' + export async function truncateAndInvalidate( queryClient: QueryClient, queryKey: QueryKey, @@ -44,7 +46,7 @@ export function didOrHandleUriMatches( export function getEmbeddedPost( v: unknown, ): AppBskyEmbedRecord.ViewRecord | undefined { - if (AppBskyEmbedRecord.isValidView(v)) { + if (atp.fastIsType(v, AppBskyEmbedRecord.isView)) { if ( AppBskyEmbedRecord.isViewRecord(v.record) && AppBskyFeedPost.isRecord(v.record.value) @@ -52,7 +54,12 @@ export function getEmbeddedPost( return v.record } } - if (AppBskyEmbedRecordWithMedia.isValidView(v)) { + if ( + atp.fastIsType( + v, + AppBskyEmbedRecordWithMedia.isView, + ) + ) { if ( AppBskyEmbedRecord.isViewRecord(v.record.record) && AppBskyFeedPost.isRecord(v.record.record.value) From 31ae18591cc8fdfcb103b9112f2719765aef50a4 Mon Sep 17 00:00:00 2001 From: Matthieu Sieben Date: Tue, 7 Jan 2025 17:19:52 +0100 Subject: [PATCH 048/142] suggestions (#7382) * suggestions * Revert unneeded changes --------- Co-authored-by: Eric Bailey --- src/lib/strings/embed-player.ts | 9 +++++++++ src/screens/Messages/components/MessageInputEmbed.tsx | 6 +----- src/types/atproto/index.ts | 4 ++-- src/types/atproto/profile.ts | 6 ++---- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/lib/strings/embed-player.ts b/src/lib/strings/embed-player.ts index 9ee5128c89..0b3073b95d 100644 --- a/src/lib/strings/embed-player.ts +++ b/src/lib/strings/embed-player.ts @@ -568,3 +568,12 @@ export function parseTenorGif(urlp: URL): dimensions, } } + +export function isTenorGifUri(url: URL | string) { + try { + return parseTenorGif(typeof url === 'string' ? new URL(url) : url).success + } catch { + // Invalid URL + return false + } +} diff --git a/src/screens/Messages/components/MessageInputEmbed.tsx b/src/screens/Messages/components/MessageInputEmbed.tsx index 6df0ef2fc8..827c62f061 100644 --- a/src/screens/Messages/components/MessageInputEmbed.tsx +++ b/src/screens/Messages/components/MessageInputEmbed.tsx @@ -111,11 +111,7 @@ export function MessageInputEmbed({ ) const {rt, record} = useMemo(() => { - if ( - post && - AppBskyFeedPost.isRecord(post.record) && - AppBskyFeedPost.validateRecord(post.record).success - ) { + if (post && AppBskyFeedPost.isValidRecord(post.record)) { return { rt: new RichTextAPI({ text: post.record.text, diff --git a/src/types/atproto/index.ts b/src/types/atproto/index.ts index 0f17653cc7..75f78d7b11 100644 --- a/src/types/atproto/index.ts +++ b/src/types/atproto/index.ts @@ -16,9 +16,9 @@ export * as profile from '#/types/atproto/profile' * } * ``` */ -export function fastIsType( +export function fastIsType( record: unknown, - identity: (v: V) => boolean, + identity: (v: V) => v is V & {$type: NonNullable}, ): record is R { return identity(record) } diff --git a/src/types/atproto/profile.ts b/src/types/atproto/profile.ts index fd3a0c0816..55881fe126 100644 --- a/src/types/atproto/profile.ts +++ b/src/types/atproto/profile.ts @@ -42,10 +42,8 @@ export function anyToBasic( associated: view.associated, viewer: view.viewer, labels: view.labels, - // @ts-expect-error `createdAt` doesn't exist on chat view - createdAt: ChatBskyActorDefs.isProfileViewBasic(view) - ? undefined - : view.createdAt, + // `createdAt` doesn't exist in ChatBskyActorDefs.ProfileViewBasic + createdAt: 'createdAt' in view ? view.createdAt : undefined, } } From 1c8b9899bd72f46d7c87f32834ef02ef4f05e773 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 10:32:34 -0600 Subject: [PATCH 049/142] Use new util --- src/components/MediaPreview.tsx | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/src/components/MediaPreview.tsx b/src/components/MediaPreview.tsx index 9d9c755456..96fb0b2812 100644 --- a/src/components/MediaPreview.tsx +++ b/src/components/MediaPreview.tsx @@ -4,7 +4,7 @@ import {Image} from 'expo-image' import {AppBskyFeedDefs} from '@atproto/api' import {Trans} from '@lingui/macro' -import {parseTenorGif} from '#/lib/strings/embed-player' +import {isTenorGifUri} from '#/lib/strings/embed-player' import {atoms as a, useTheme} from '#/alf' import {MediaInsetBorder} from '#/components/MediaInsetBorder' import {Text} from '#/components/Typography' @@ -37,24 +37,17 @@ export function Embed({ ))} ) - } else if (e.type === 'link' && e.view.external.thumb) { - let url: URL | undefined - try { - url = new URL(e.view.external.uri) - } catch {} - if (url) { - const {success} = parseTenorGif(url) - if (success) { - return ( - - - - ) - } - } + } else if (e.type === 'link') { + if (!e.view.external.thumb) return null + if (!isTenorGifUri(e.view.external.uri)) return null + return ( + + + + ) } else if (e.type === 'video') { return ( From 248bff26e1adabc756675e8d6a06163f7a769064 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 10:35:20 -0600 Subject: [PATCH 050/142] Rename to dangerousIsType --- src/state/queries/post-thread.ts | 2 +- src/state/queries/util.ts | 6 ++++-- src/types/atproto/index.ts | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/state/queries/post-thread.ts b/src/state/queries/post-thread.ts index beb50752d0..3f845e3ed3 100644 --- a/src/state/queries/post-thread.ts +++ b/src/state/queries/post-thread.ts @@ -330,7 +330,7 @@ function responseToThreadNodes( ): ThreadNode { if ( AppBskyFeedDefs.isThreadViewPost(node) && - atp.fastIsType( + atp.dangerousIsType( node.post.record, AppBskyFeedPost.isRecord, ) diff --git a/src/state/queries/util.ts b/src/state/queries/util.ts index 081cb82ecc..e299f013db 100644 --- a/src/state/queries/util.ts +++ b/src/state/queries/util.ts @@ -46,7 +46,9 @@ export function didOrHandleUriMatches( export function getEmbeddedPost( v: unknown, ): AppBskyEmbedRecord.ViewRecord | undefined { - if (atp.fastIsType(v, AppBskyEmbedRecord.isView)) { + if ( + atp.dangerousIsType(v, AppBskyEmbedRecord.isView) + ) { if ( AppBskyEmbedRecord.isViewRecord(v.record) && AppBskyFeedPost.isRecord(v.record.value) @@ -55,7 +57,7 @@ export function getEmbeddedPost( } } if ( - atp.fastIsType( + atp.dangerousIsType( v, AppBskyEmbedRecordWithMedia.isView, ) diff --git a/src/types/atproto/index.ts b/src/types/atproto/index.ts index 75f78d7b11..18db966ac8 100644 --- a/src/types/atproto/index.ts +++ b/src/types/atproto/index.ts @@ -12,11 +12,11 @@ export * as profile from '#/types/atproto/profile' * ```ts * import * as atp from '#/types/atproto' * - * if (atp.fastIsType(node.post.record, AppBskyFeedPost.isRecord)) { + * if (atp.dangerousIsType(node.post.record, AppBskyFeedPost.isRecord)) { * } * ``` */ -export function fastIsType( +export function dangerousIsType( record: unknown, identity: (v: V) => v is V & {$type: NonNullable}, ): record is R { From 964fc202449882aca07f67419c11c57b6371a15d Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 10:37:08 -0600 Subject: [PATCH 051/142] Convert object shape --- src/view/com/notifications/NotificationFeedItem.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/view/com/notifications/NotificationFeedItem.tsx b/src/view/com/notifications/NotificationFeedItem.tsx index 2a6ad135e4..938f9975a7 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 atp from '#/types/atproto' import {FeedSourceCard} from '../feeds/FeedSourceCard' import {Post} from '../post/Post' import {Link, TextLink} from '../util/Link' @@ -124,8 +125,10 @@ let NotificationFeedItem = ({ * 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) + precacheProfile( + queryClient, + atp.profile.anyToBasic(item.notification.author), + ) }, [queryClient, item.notification.author]) const authors: Author[] = useMemo(() => { From 31673b64580d0515f1ba74bbec60522c30d4c84c Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 10:38:55 -0600 Subject: [PATCH 052/142] Use dangerous util --- src/view/com/notifications/NotificationFeedItem.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/view/com/notifications/NotificationFeedItem.tsx b/src/view/com/notifications/NotificationFeedItem.tsx index 938f9975a7..658518bc89 100644 --- a/src/view/com/notifications/NotificationFeedItem.tsx +++ b/src/view/com/notifications/NotificationFeedItem.tsx @@ -272,7 +272,10 @@ let NotificationFeedItem = ({ if ( item.notification.author.viewer?.following && - AppBskyGraphFollow.isValidRecord(item.notification.record) + atp.dangerousIsType( + item.notification.record, + AppBskyGraphFollow.isRecord, + ) ) { let followingTimestamp try { @@ -724,7 +727,13 @@ function ExpandedAuthorsList({ function AdditionalPostText({post}: {post?: AppBskyFeedDefs.PostView}) { const pal = usePalette('default') - if (post && AppBskyFeedPost.isValidRecord(post?.record)) { + if ( + post && + atp.dangerousIsType( + post?.record, + AppBskyFeedPost.isRecord, + ) + ) { const text = post.record.text return ( From 44cb25d3a18f9614395e092d9683d04956f18d4a Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 10:40:40 -0600 Subject: [PATCH 053/142] Use dangerous util --- src/view/com/post-thread/PostThreadItem.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx index c68421b634..d88ec66880 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 atp from '#/types/atproto' export function PostThreadItem({ post, @@ -785,7 +786,10 @@ function BackdatedPostIndicator({post}: {post: AppBskyFeedDefs.PostView}) { const control = Prompt.usePromptControl() const indexedAt = new Date(post.indexedAt) - const createdAt = AppBskyFeedPost.isValidRecord(post.record) + const createdAt = atp.dangerousIsType( + post.record, + AppBskyFeedPost.isRecord, + ) ? new Date(post.record.createdAt) : new Date(post.indexedAt) From e2c360044718086699e2b6251541e575f5ad60a5 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 10:42:10 -0600 Subject: [PATCH 054/142] Use dangerous util, we can trust post records --- src/view/com/post/Post.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx index bf256a4924..cdd9fd41ea 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 atp from '#/types/atproto' import {ContentHider} from '../../../components/moderation/ContentHider' import {LabelsOnMyPost} from '../../../components/moderation/LabelsOnMe' import {PostAlerts} from '../../../components/moderation/PostAlerts' @@ -53,7 +54,12 @@ export function Post({ const moderationOpts = useModerationOpts() const record = useMemo( () => - AppBskyFeedPost.isValidRecord(post.record) ? post.record : undefined, + atp.dangerousIsType( + post.record, + AppBskyFeedPost.isRecord, + ) + ? post.record + : undefined, [post], ) const postShadowed = usePostShadow(post) From 7dcf6b8de4425273b9cc363cbbf26114280bf2af Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 10:45:18 -0600 Subject: [PATCH 055/142] Use dangerous util --- src/view/com/posts/PostFeedItem.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/view/com/posts/PostFeedItem.tsx b/src/view/com/posts/PostFeedItem.tsx index 8d6f41ac6b..6aa1642db0 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 atp from '#/types/atproto' 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.isValidRecord( + const threadgateRecord = atp.dangerousIsType( 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.isValidRecord(post.record) + const rootPostUri = atp.dangerousIsType( + post.record, + AppBskyFeedPost.isRecord, + ) ? post.record?.reply?.root?.uri || post.uri : undefined const isControlledByViewer = From 9990c833cf9e8b8ea4bedbffd2ad7727def7fc52 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 10:46:44 -0600 Subject: [PATCH 056/142] Use AnyProfileVIew --- src/view/com/util/UserAvatar.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index 2e4b4e6f0b..b583ae8acf 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 atp from '#/types/atproto' import {openCamera, openCropper, openPicker} from '../../../lib/media/picker' export type UserAvatarType = 'user' | 'algo' | 'list' | 'labeler' @@ -54,7 +55,7 @@ interface EditableUserAvatarProps extends BaseUserAvatarProps { interface PreviewableUserAvatarProps extends BaseUserAvatarProps { moderation?: ModerationUI - profile: Omit + profile: atp.profile.AnyProfileView disableHoverCard?: boolean onBeforePress?: () => void } From a5e03d13c22769a0cfff002bc63a44b13fc9c6da Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 10:48:32 -0600 Subject: [PATCH 057/142] Convert object shape --- src/view/com/util/UserAvatar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index b583ae8acf..1685ac9583 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -427,7 +427,7 @@ let PreviewableUserAvatar = ({ const onPress = React.useCallback(() => { onBeforePress?.() - precacheProfile(queryClient, profile) + precacheProfile(queryClient, atp.profile.anyToBasic(profile)) }, [profile, queryClient, onBeforePress]) return ( From 9499e2fc8525d6fe81293686c5ed53a03719fd65 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 10:50:38 -0600 Subject: [PATCH 058/142] Clean up handling --- src/view/com/util/post-embeds/QuoteEmbed.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/view/com/util/post-embeds/QuoteEmbed.tsx b/src/view/com/util/post-embeds/QuoteEmbed.tsx index 91909ce950..6622ff98a2 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 atp from '#/types/atproto' import {ContentHider} from '../../../../components/moderation/ContentHider' import {PostAlerts} from '../../../../components/moderation/PostAlerts' import {Link} from '../Link' @@ -171,12 +172,14 @@ export function QuoteEmbed({ const itemTitle = `Post by ${quote.author.handle}` const richText = React.useMemo(() => { - const text = AppBskyFeedPost.isValidRecord(quote.record) - ? quote.record.text - : '' - const facets = AppBskyFeedPost.isValidRecord(quote.record) - ? quote.record.facets - : undefined + if ( + !atp.dangerousIsType( + quote.record, + AppBskyFeedPost.isRecord, + ) + ) + return undefined + const {text, facets} = quote.record return text.trim() ? new RichTextAPI({text: text, facets: facets}) : undefined From 54a5d564476ef6821a77e9c1ead3505589a0c1bc Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 11:30:11 -0600 Subject: [PATCH 059/142] Patch moderateProfile to accept known profile views, to discuss --- patches/@atproto+api+0.14.0-next.1.patch | 39 +++++++++++++++++++ .../Messages/components/ChatListItem.tsx | 4 +- 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 patches/@atproto+api+0.14.0-next.1.patch diff --git a/patches/@atproto+api+0.14.0-next.1.patch b/patches/@atproto+api+0.14.0-next.1.patch new file mode 100644 index 0000000000..675e1aa7ea --- /dev/null +++ b/patches/@atproto+api+0.14.0-next.1.patch @@ -0,0 +1,39 @@ +diff --git a/node_modules/@atproto/api/dist/moderation/types.d.ts b/node_modules/@atproto/api/dist/moderation/types.d.ts +index 4b1ebdd..33f6fb5 100644 +--- a/node_modules/@atproto/api/dist/moderation/types.d.ts ++++ b/node_modules/@atproto/api/dist/moderation/types.d.ts +@@ -1,4 +1,4 @@ +-import { AppBskyActorDefs, AppBskyFeedDefs, AppBskyNotificationListNotifications, AppBskyGraphDefs, ComAtprotoLabelDefs } from '../client/index'; ++import { AppBskyActorDefs, AppBskyFeedDefs, AppBskyNotificationListNotifications, AppBskyGraphDefs, ComAtprotoLabelDefs, ChatBskyActorDefs } from '../client/index'; + import { KnownLabelValue } from './const/labels'; + export declare const CUSTOM_LABEL_VALUE_RE: RegExp; + export interface ModerationBehavior { +@@ -32,7 +32,7 @@ export interface InterpretedLabelValueDefinition extends ComAtprotoLabelDefs.Lab + }; + } + export type LabelDefinitionMap = Record; +-export type ModerationSubjectProfile = AppBskyActorDefs.ProfileViewBasic | AppBskyActorDefs.ProfileView | AppBskyActorDefs.ProfileViewDetailed; ++export type ModerationSubjectProfile = AppBskyActorDefs.ProfileViewBasic | AppBskyActorDefs.ProfileView | AppBskyActorDefs.ProfileViewDetailed | ChatBskyActorDefs.ProfileViewBasic; + export type ModerationSubjectPost = AppBskyFeedDefs.PostView; + export type ModerationSubjectNotification = AppBskyNotificationListNotifications.Notification; + export type ModerationSubjectFeedGenerator = AppBskyFeedDefs.GeneratorView; +diff --git a/node_modules/@atproto/api/src/moderation/types.ts b/node_modules/@atproto/api/src/moderation/types.ts +index bbf8d84..16293e2 100644 +--- a/node_modules/@atproto/api/src/moderation/types.ts ++++ b/node_modules/@atproto/api/src/moderation/types.ts +@@ -4,6 +4,7 @@ import { + AppBskyNotificationListNotifications, + AppBskyGraphDefs, + ComAtprotoLabelDefs, ++ ChatBskyActorDefs, + } from '../client/index' + import { KnownLabelValue } from './const/labels' + +@@ -87,6 +88,7 @@ export type ModerationSubjectProfile = + | AppBskyActorDefs.ProfileViewBasic + | AppBskyActorDefs.ProfileView + | AppBskyActorDefs.ProfileViewDetailed ++ | ChatBskyActorDefs.ProfileViewBasic + + export type ModerationSubjectPost = AppBskyFeedDefs.PostView + diff --git a/src/screens/Messages/components/ChatListItem.tsx b/src/screens/Messages/components/ChatListItem.tsx index 6b8deea30e..599418ca47 100644 --- a/src/screens/Messages/components/ChatListItem.tsx +++ b/src/screens/Messages/components/ChatListItem.tsx @@ -1,7 +1,6 @@ import React, {useCallback, useMemo, useState} from 'react' import {GestureResponderEvent, View} from 'react-native' import { - AppBskyActorDefs, AppBskyEmbedRecord, ChatBskyConvoDefs, moderateProfile, @@ -39,6 +38,7 @@ import {Link} from '#/components/Link' import {useMenuControl} from '#/components/Menu' import {PostAlerts} from '#/components/moderation/PostAlerts' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' export let ChatListItem = ({ convo, @@ -73,7 +73,7 @@ function ChatListItemReady({ moderationOpts, }: { convo: ChatBskyConvoDefs.ConvoView - profile: AppBskyActorDefs.ProfileViewBasic + profile: atp.profile.AnyProfileView moderationOpts: ModerationOpts }) { const t = useTheme() From 4a1695b7983366d5fb8f80bc5ebabdad58e832c3 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 11:57:52 -0600 Subject: [PATCH 060/142] Add AnyStarterPackView and related, implement in first usage --- .../StarterPack/StarterPackCard.tsx | 20 +++++++++++------- src/lib/strings/starter-pack.ts | 6 ++++-- src/types/atproto/index.ts | 1 + src/types/atproto/starterPack.ts | 21 +++++++++++++++++++ 4 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 src/types/atproto/starterPack.ts diff --git a/src/components/StarterPack/StarterPackCard.tsx b/src/components/StarterPack/StarterPackCard.tsx index 22e0a155ab..72deca9f6b 100644 --- a/src/components/StarterPack/StarterPackCard.tsx +++ b/src/components/StarterPack/StarterPackCard.tsx @@ -1,7 +1,7 @@ import React from 'react' import {View} from 'react-native' import {Image} from 'expo-image' -import {AppBskyGraphDefs, AppBskyGraphStarterpack, AtUri} from '@atproto/api' +import {AppBskyGraphStarterpack, AtUri} from '@atproto/api' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useQueryClient} from '@tanstack/react-query' @@ -15,11 +15,12 @@ import {atoms as a, useTheme} from '#/alf' import {StarterPack} from '#/components/icons/StarterPack' import {Link as BaseLink, LinkProps as BaseLinkProps} from '#/components/Link' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' export function Default({ starterPack, }: { - starterPack?: AppBskyGraphDefs.StarterPackViewBasic + starterPack?: atp.starterPack.AnyStarterPackView }) { if (!starterPack) return null return ( @@ -32,7 +33,7 @@ export function Default({ export function Notification({ starterPack, }: { - starterPack?: AppBskyGraphDefs.StarterPackViewBasic + starterPack?: atp.starterPack.AnyStarterPackView }) { if (!starterPack) return null return ( @@ -47,7 +48,7 @@ export function Card({ noIcon, noDescription, }: { - starterPack: AppBskyGraphDefs.StarterPackViewBasic + starterPack: atp.starterPack.AnyStarterPackView noIcon?: boolean noDescription?: boolean }) { @@ -57,7 +58,12 @@ export function Card({ const t = useTheme() const {currentAccount} = useSession() - if (!AppBskyGraphStarterpack.isRecord(record)) { + if ( + !atp.dangerousIsType( + record, + AppBskyGraphStarterpack.isRecord, + ) + ) { return null } @@ -100,7 +106,7 @@ export function Link({ starterPack, children, }: { - starterPack: AppBskyGraphDefs.StarterPackViewBasic + starterPack: atp.starterPack.AnyStarterPackView onPress?: () => void children: BaseLinkProps['children'] }) { @@ -139,7 +145,7 @@ export function Link({ export function Embed({ starterPack, }: { - starterPack: AppBskyGraphDefs.StarterPackViewBasic + starterPack: atp.starterPack.AnyStarterPackView }) { const t = useTheme() const imageUri = getStarterPackOgCard(starterPack) diff --git a/src/lib/strings/starter-pack.ts b/src/lib/strings/starter-pack.ts index ca34100155..2e4497a443 100644 --- a/src/lib/strings/starter-pack.ts +++ b/src/lib/strings/starter-pack.ts @@ -1,4 +1,6 @@ -import {AppBskyGraphDefs, AtUri} from '@atproto/api' +import {AtUri} from '@atproto/api' + +import * as atp from '#/types/atproto' export function createStarterPackLinkFromAndroidReferrer( referrerQueryString: string, @@ -79,7 +81,7 @@ export function httpStarterPackUriToAtUri(httpUri?: string): string | null { } export function getStarterPackOgCard( - didOrStarterPack: AppBskyGraphDefs.StarterPackView | string, + didOrStarterPack: atp.starterPack.AnyStarterPackView | string, rkey?: string, ) { if (typeof didOrStarterPack === 'string') { diff --git a/src/types/atproto/index.ts b/src/types/atproto/index.ts index 18db966ac8..ee24ab1e3d 100644 --- a/src/types/atproto/index.ts +++ b/src/types/atproto/index.ts @@ -1,4 +1,5 @@ export * as profile from '#/types/atproto/profile' +export * as starterPack from '#/types/atproto/starterPack' /** * Use sparingly, and only when you know it's safe to do so. diff --git a/src/types/atproto/starterPack.ts b/src/types/atproto/starterPack.ts new file mode 100644 index 0000000000..513b4750bd --- /dev/null +++ b/src/types/atproto/starterPack.ts @@ -0,0 +1,21 @@ +import {AppBskyGraphDefs} from '@atproto/api' + +export { + /** + * Renamed to clarify source of this util, but directly aliases the original. + * {@link AppBskyGraphDefs.isStarterPackViewBasic} + */ + isStarterPackViewBasic as isBasicView, + /** + * Renamed to clarify source of this util, but directly aliases the original. + * {@link AppBskyGraphDefs.isStarterPackView} + */ + isStarterPackView as isView, +} from '@atproto/api/dist/client/types/app/bsky/graph/defs' + +/** + * Matches any starter pack view exported by our SDK + */ +export type AnyStarterPackView = + | AppBskyGraphDefs.StarterPackViewBasic + | AppBskyGraphDefs.StarterPackView From 5dbb2c2b4cd282e9fcf76723218952d1418ac088 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 12:46:21 -0600 Subject: [PATCH 061/142] Remove validation, fix type, fix ref --- src/state/queries/notifications/util.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/state/queries/notifications/util.ts b/src/state/queries/notifications/util.ts index 0ffa7302dc..339a341d0f 100644 --- a/src/state/queries/notifications/util.ts +++ b/src/state/queries/notifications/util.ts @@ -206,12 +206,9 @@ async function fetchSubjects( ), ) const postsMap = new Map() - const packsMap = new Map() + const packsMap = new Map() for (const post of postsChunks.flat()) { - if ( - AppBskyFeedPost.isRecord(post.record) && - AppBskyFeedPost.validateRecord(post.record).success - ) { + if (AppBskyFeedPost.isRecord(post.record)) { postsMap.set(post.uri, post) } } @@ -256,11 +253,11 @@ function getSubjectUri( return notif.uri } else if (type === 'post-like' || type === 'repost') { if ( - atp.fastIsType( + atp.dangerousIsType( notif.record, AppBskyFeedRepost.isRecord, ) || - atp.fastIsType( + atp.dangerousIsType( notif.record, AppBskyFeedLike.isRecord, ) From 23672e0afc381cacf543607ae2dab03c52246950 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 14:11:13 -0600 Subject: [PATCH 062/142] Migrate over list-conversations --- .../queries/messages/list-conversations.tsx | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/state/queries/messages/list-conversations.tsx b/src/state/queries/messages/list-conversations.tsx index ae379f9628..63074b321a 100644 --- a/src/state/queries/messages/list-conversations.tsx +++ b/src/state/queries/messages/list-conversations.tsx @@ -110,15 +110,24 @@ export function ListConvosProviderInner({ ) } else if (ChatBskyConvoDefs.isLogDeleteMessage(log)) { queryClient.setQueryData(RQKEY, (old: ConvoListQueryData) => - optimisticUpdate(log.convoId, old, convo => - log.message.id === convo.lastMessage?.id - ? { - ...convo, - rev: log.rev, - lastMessage: log.message, - } - : convo, - ), + optimisticUpdate(log.convoId, old, convo => { + if ( + (ChatBskyConvoDefs.isDeletedMessageView(log.message) || + ChatBskyConvoDefs.isMessageView(log.message)) && + (ChatBskyConvoDefs.isDeletedMessageView(convo.lastMessage) || + ChatBskyConvoDefs.isMessageView(convo.lastMessage)) + ) { + return log.message.id === convo.lastMessage.id + ? { + ...convo, + rev: log.rev, + lastMessage: log.message, + } + : convo + } else { + return convo + } + }), ) } else if (ChatBskyConvoDefs.isLogCreateMessage(log)) { queryClient.setQueryData(RQKEY, (old: ConvoListQueryData) => { @@ -152,7 +161,11 @@ export function ListConvosProviderInner({ function filterConvoFromPage( convo: ChatBskyConvoDefs.ConvoView[], ) { - return convo.filter(c => c.id !== log.convoId) + return convo.filter( + c => + c.id !== + (log as ChatBskyConvoDefs.LogCreateMessage).convoId, + ) } const existingConvo = getConvoFromQueryData(log.convoId, old) From 283a647539a36f6a288624c03f53982711d7e1db Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 15:23:24 -0600 Subject: [PATCH 063/142] Clarify intent behind precacheProfile and its unstable query cache --- src/state/queries/profile.ts | 34 +++++++++++---- src/state/queries/resolve-uri.ts | 13 +++--- src/types/atproto/profile.ts | 41 ------------------- .../notifications/NotificationFeedItem.tsx | 9 +--- src/view/com/profile/ProfileCard.tsx | 2 +- src/view/com/util/UserAvatar.tsx | 2 +- 6 files changed, 35 insertions(+), 66 deletions(-) diff --git a/src/state/queries/profile.ts b/src/state/queries/profile.ts index 42dddbb975..a5edd9b405 100644 --- a/src/state/queries/profile.ts +++ b/src/state/queries/profile.ts @@ -44,9 +44,13 @@ export const profilesQueryKey = (handles: string[]) => [ handles, ] -const profileBasicQueryKeyRoot = 'profileBasic' -export const profileBasicQueryKey = (didOrHandle: string) => [ - profileBasicQueryKeyRoot, +const unstableProfileViewCacheQueryKeyRoot = 'unstableProfileViewCache' +/** + * We cache multiple profile view types by this query key. If object shapes are + * important, you should validate the type when accessing the data. + */ +export const unstableProfileViewCacheQueryKey = (didOrHandle: string) => [ + unstableProfileViewCacheQueryKeyRoot, didOrHandle, ] @@ -74,9 +78,10 @@ export function useProfileQuery({ placeholderData: () => { if (!did) return - return queryClient.getQueryData( - profileBasicQueryKey(did), - ) + // This can return any profile view type + return queryClient.getQueryData( + unstableProfileViewCacheQueryKey(did), + ) as AppBskyActorDefs.ProfileViewDetailed }, enabled: !!did, }) @@ -507,12 +512,23 @@ function useProfileUnblockMutation() { }) } +/** + * This function is used to precache a profile view in the query client. Any + * profile view type is accepted, so you should validate the type when + * accessing the data. + */ export function precacheProfile( queryClient: QueryClient, - profile: AppBskyActorDefs.ProfileViewBasic, + profile: atp.profile.AnyProfileView, ) { - queryClient.setQueryData(profileBasicQueryKey(profile.handle), profile) - queryClient.setQueryData(profileBasicQueryKey(profile.did), profile) + queryClient.setQueryData( + unstableProfileViewCacheQueryKey(profile.handle), + profile, + ) + queryClient.setQueryData( + unstableProfileViewCacheQueryKey(profile.did), + profile, + ) } async function whenAppViewReady( diff --git a/src/state/queries/resolve-uri.ts b/src/state/queries/resolve-uri.ts index c1fd8e240a..8efa630599 100644 --- a/src/state/queries/resolve-uri.ts +++ b/src/state/queries/resolve-uri.ts @@ -1,4 +1,4 @@ -import {AppBskyActorDefs, AtUri} from '@atproto/api' +import {AtUri} from '@atproto/api' import { QueryClient, useQuery, @@ -8,7 +8,8 @@ import { import {STALE} from '#/state/queries' import {useAgent} from '#/state/session' -import {profileBasicQueryKey as RQKEY_PROFILE_BASIC} from './profile' +import * as atp from '#/types/atproto' +import {unstableProfileViewCacheQueryKey} from './profile' const RQKEY_ROOT = 'resolved-did' export const RQKEY = (didOrHandle: string) => [RQKEY_ROOT, didOrHandle] @@ -46,10 +47,10 @@ export function useResolveDidQuery(didOrHandle: string | undefined) { // Return undefined if no did or handle if (!didOrHandle) return - const profile = - queryClient.getQueryData( - RQKEY_PROFILE_BASIC(didOrHandle), - ) + // This can return any profile view type + const profile = queryClient.getQueryData( + unstableProfileViewCacheQueryKey(didOrHandle), + ) return profile?.did }, enabled: !!didOrHandle, diff --git a/src/types/atproto/profile.ts b/src/types/atproto/profile.ts index 55881fe126..7c0aae287e 100644 --- a/src/types/atproto/profile.ts +++ b/src/types/atproto/profile.ts @@ -26,44 +26,3 @@ export type AnyProfileView = | AppBskyActorDefs.ProfileView | AppBskyActorDefs.ProfileViewDetailed | ChatBskyActorDefs.ProfileViewBasic - -/** - * 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` doesn't exist in ChatBskyActorDefs.ProfileViewBasic - createdAt: 'createdAt' in view ? view.createdAt : undefined, - } -} - -/** - * 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, - } -} diff --git a/src/view/com/notifications/NotificationFeedItem.tsx b/src/view/com/notifications/NotificationFeedItem.tsx index 658518bc89..186d054fca 100644 --- a/src/view/com/notifications/NotificationFeedItem.tsx +++ b/src/view/com/notifications/NotificationFeedItem.tsx @@ -121,14 +121,7 @@ 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. - */ - precacheProfile( - queryClient, - atp.profile.anyToBasic(item.notification.author), - ) + precacheProfile(queryClient, item.notification.author) }, [queryClient, item.notification.author]) const authors: Author[] = useMemo(() => { diff --git a/src/view/com/profile/ProfileCard.tsx b/src/view/com/profile/ProfileCard.tsx index 8a258498fb..f5376b4798 100644 --- a/src/view/com/profile/ProfileCard.tsx +++ b/src/view/com/profile/ProfileCard.tsx @@ -61,7 +61,7 @@ export function ProfileCard({ const onBeforePress = React.useCallback(() => { onPress?.() - precacheProfile(queryClient, atp.profile.anyToBasic(profile)) + precacheProfile(queryClient, profile) }, [onPress, profile, queryClient]) if (!moderationOpts) { diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index 1685ac9583..b583ae8acf 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -427,7 +427,7 @@ let PreviewableUserAvatar = ({ const onPress = React.useCallback(() => { onBeforePress?.() - precacheProfile(queryClient, atp.profile.anyToBasic(profile)) + precacheProfile(queryClient, profile) }, [profile, queryClient, onBeforePress]) return ( From e0344434c957327e03379c8b5aee7992619deb8e Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 15:50:29 -0600 Subject: [PATCH 064/142] Clean up unstable profile cache --- src/state/queries/profile.ts | 47 +++++-------------- src/state/queries/resolve-uri.ts | 18 ++------ src/state/queries/unstable-profile-cache.ts | 51 +++++++++++++++++++++ 3 files changed, 67 insertions(+), 49 deletions(-) create mode 100644 src/state/queries/unstable-profile-cache.ts diff --git a/src/state/queries/profile.ts b/src/state/queries/profile.ts index a5edd9b405..5ac50fba55 100644 --- a/src/state/queries/profile.ts +++ b/src/state/queries/profile.ts @@ -23,6 +23,10 @@ import {logEvent, LogEvents, toClout} from '#/lib/statsig/statsig' import {Shadow} from '#/state/cache/types' import {STALE} from '#/state/queries' import {resetProfilePostsQueries} from '#/state/queries/post-feed' +import { + unstableCacheProfileView, + useUnstableProfileViewCache, +} from '#/state/queries/unstable-profile-cache' import * as userActionHistory from '#/state/userActionHistory' import * as atp from '#/types/atproto' import {updateProfileShadow} from '../cache/profile-shadow' @@ -35,6 +39,12 @@ import {RQKEY as RQKEY_LIST_CONVOS} from './messages/list-conversations' import {RQKEY as RQKEY_MY_BLOCKED} from './my-blocked-accounts' import {RQKEY as RQKEY_MY_MUTED} from './my-muted-accounts' +export * from '#/state/queries/unstable-profile-cache' +/** + * @deprecated use {@link unstableCacheProfileView} instead + */ +export const precacheProfile = unstableCacheProfileView + const RQKEY_ROOT = 'profile' export const RQKEY = (did: string) => [RQKEY_ROOT, did] @@ -44,16 +54,6 @@ export const profilesQueryKey = (handles: string[]) => [ handles, ] -const unstableProfileViewCacheQueryKeyRoot = 'unstableProfileViewCache' -/** - * We cache multiple profile view types by this query key. If object shapes are - * important, you should validate the type when accessing the data. - */ -export const unstableProfileViewCacheQueryKey = (didOrHandle: string) => [ - unstableProfileViewCacheQueryKeyRoot, - didOrHandle, -] - export function useProfileQuery({ did, staleTime = STALE.SECONDS.FIFTEEN, @@ -61,8 +61,8 @@ export function useProfileQuery({ did: string | undefined staleTime?: number }) { - const queryClient = useQueryClient() const agent = useAgent() + const {getUnstableProfile} = useUnstableProfileViewCache() return useQuery({ // WARNING // this staleTime is load-bearing @@ -77,11 +77,7 @@ export function useProfileQuery({ }, placeholderData: () => { if (!did) return - - // This can return any profile view type - return queryClient.getQueryData( - unstableProfileViewCacheQueryKey(did), - ) as AppBskyActorDefs.ProfileViewDetailed + return getUnstableProfile(did) as AppBskyActorDefs.ProfileViewDetailed }, enabled: !!did, }) @@ -512,25 +508,6 @@ function useProfileUnblockMutation() { }) } -/** - * This function is used to precache a profile view in the query client. Any - * profile view type is accepted, so you should validate the type when - * accessing the data. - */ -export function precacheProfile( - queryClient: QueryClient, - profile: atp.profile.AnyProfileView, -) { - queryClient.setQueryData( - unstableProfileViewCacheQueryKey(profile.handle), - profile, - ) - queryClient.setQueryData( - unstableProfileViewCacheQueryKey(profile.did), - profile, - ) -} - async function whenAppViewReady( agent: BskyAgent, actor: string, diff --git a/src/state/queries/resolve-uri.ts b/src/state/queries/resolve-uri.ts index 8efa630599..1422a2daef 100644 --- a/src/state/queries/resolve-uri.ts +++ b/src/state/queries/resolve-uri.ts @@ -1,15 +1,9 @@ import {AtUri} from '@atproto/api' -import { - QueryClient, - useQuery, - useQueryClient, - UseQueryResult, -} from '@tanstack/react-query' +import {QueryClient, useQuery, UseQueryResult} from '@tanstack/react-query' import {STALE} from '#/state/queries' import {useAgent} from '#/state/session' -import * as atp from '#/types/atproto' -import {unstableProfileViewCacheQueryKey} from './profile' +import {useUnstableProfileViewCache} from './profile' const RQKEY_ROOT = 'resolved-did' export const RQKEY = (didOrHandle: string) => [RQKEY_ROOT, didOrHandle] @@ -29,8 +23,8 @@ export function useResolveUriQuery(uri: string | undefined): UriUseQueryResult { } export function useResolveDidQuery(didOrHandle: string | undefined) { - const queryClient = useQueryClient() const agent = useAgent() + const {getUnstableProfile} = useUnstableProfileViewCache() return useQuery({ staleTime: STALE.HOURS.ONE, @@ -46,11 +40,7 @@ export function useResolveDidQuery(didOrHandle: string | undefined) { initialData: () => { // Return undefined if no did or handle if (!didOrHandle) return - - // This can return any profile view type - const profile = queryClient.getQueryData( - unstableProfileViewCacheQueryKey(didOrHandle), - ) + const profile = getUnstableProfile(didOrHandle) return profile?.did }, enabled: !!didOrHandle, diff --git a/src/state/queries/unstable-profile-cache.ts b/src/state/queries/unstable-profile-cache.ts new file mode 100644 index 0000000000..40eae6dcda --- /dev/null +++ b/src/state/queries/unstable-profile-cache.ts @@ -0,0 +1,51 @@ +import {useCallback} from 'react' +import {QueryClient,useQueryClient} from '@tanstack/react-query' + +import * as atp from '#/types/atproto' + +const unstableProfileViewCacheQueryKeyRoot = 'unstableProfileViewCache' +export const unstableProfileViewCacheQueryKey = (didOrHandle: string) => [ + unstableProfileViewCacheQueryKeyRoot, + didOrHandle, +] + +/** + * Used as a rough cache of profile views to make loading snappier. This method + * accepts and stores any profile view type by both handle and DID. + * + * Access the cache via {@link useUnstableProfileViewCache}. + */ +export function unstableCacheProfileView( + queryClient: QueryClient, + profile: atp.profile.AnyProfileView, +) { + queryClient.setQueryData( + unstableProfileViewCacheQueryKey(profile.handle), + profile, + ) + queryClient.setQueryData( + unstableProfileViewCacheQueryKey(profile.did), + profile, + ) +} + +/** + * Hook to access the unstable profile view cache. This cache can return ANY + * profile view type, so if the object shape is important, you need to use the + * identity validators shipped in the atproto SDK e.g. + * `AppBskyActorDefs.isValidProfileViewBasic` to confirm before using. + * + * To cache a profile, use {@link unstableCacheProfileView}. + */ +export function useUnstableProfileViewCache() { + const qc = useQueryClient() + const getUnstableProfile = useCallback( + (didOrHandle: string) => { + return qc.getQueryData( + unstableProfileViewCacheQueryKey(didOrHandle), + ) + }, + [qc], + ) + return {getUnstableProfile} +} From 94d82535aa75a84942151a95fc3d4fc81fda012a Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 17:13:11 -0600 Subject: [PATCH 065/142] Fix types during label creation in PwiOptOut (#7346) --- src/screens/Settings/components/PwiOptOut.tsx | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/screens/Settings/components/PwiOptOut.tsx b/src/screens/Settings/components/PwiOptOut.tsx index 4339ade9be..3d236e906e 100644 --- a/src/screens/Settings/components/PwiOptOut.tsx +++ b/src/screens/Settings/components/PwiOptOut.tsx @@ -1,6 +1,7 @@ import React from 'react' import {View} from 'react-native' import {ComAtprotoLabelDefs} from '@atproto/api' +import {$Typed} from '@atproto/api/dist/client/util' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -33,31 +34,35 @@ export function PwiOptOut() { profile, updates: existing => { // create labels attr if needed - existing.labels = ComAtprotoLabelDefs.isSelfLabels(existing.labels) - ? existing.labels - : { - $type: 'com.atproto.label.defs#selfLabels', - values: [], - } + const labels: $Typed = + ComAtprotoLabelDefs.isValidSelfLabels(existing.labels) + ? existing.labels + : { + $type: 'com.atproto.label.defs#selfLabels', + values: [], + } // toggle the label - const hasLabel = existing.labels.values.some( + const hasLabel = labels.values.some( l => l.val === '!no-unauthenticated', ) if (hasLabel) { wasAdded = false - existing.labels.values = existing.labels.values.filter( + labels.values = labels.values.filter( l => l.val !== '!no-unauthenticated', ) } else { wasAdded = true - existing.labels.values.push({val: '!no-unauthenticated'}) + labels.values.push({val: '!no-unauthenticated'}) } // delete if no longer needed - if (existing.labels.values.length === 0) { + if (labels.values.length === 0) { delete existing.labels + } else { + existing.labels = labels } + return existing }, checkCommitted: res => { From 29ef63c267b3f36b8419c9e07de55465aaaf8bac Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 16:14:25 -0600 Subject: [PATCH 066/142] Tighten types in queries/list --- src/state/queries/list.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/state/queries/list.ts b/src/state/queries/list.ts index 405cb4ae3e..f2bcaf3dc7 100644 --- a/src/state/queries/list.ts +++ b/src/state/queries/list.ts @@ -5,8 +5,10 @@ import { AppBskyGraphList, AtUri, BskyAgent, + ComAtprotoRepoApplyWrites, Facet, } from '@atproto/api' +import {$Typed} from '@atproto/api/dist/client/util' import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query' import chunk from 'lodash.chunk' @@ -212,7 +214,9 @@ export function useListDeleteMutation() { } // batch delete the list and listitem records - const createDel = (uri: string) => { + const createDel = ( + uri: string, + ): $Typed => { const urip = new AtUri(uri) return { $type: 'com.atproto.repo.applyWrites#delete', From 1b13ea5ab3cb7a24efb8e5b3ca734901e591a179 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 16:19:17 -0600 Subject: [PATCH 067/142] Chat: use correct profile views --- src/state/messages/convo/agent.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/state/messages/convo/agent.ts b/src/state/messages/convo/agent.ts index 53d77046a2..d54288f500 100644 --- a/src/state/messages/convo/agent.ts +++ b/src/state/messages/convo/agent.ts @@ -1,6 +1,6 @@ import { - AppBskyActorDefs, BskyAgent, + ChatBskyActorDefs, ChatBskyConvoDefs, ChatBskyConvoGetLog, ChatBskyConvoSendMessage, @@ -80,8 +80,8 @@ export class Convo { convoId: string convo: ChatBskyConvoDefs.ConvoView | undefined - sender: AppBskyActorDefs.ProfileViewBasic | undefined - recipients: AppBskyActorDefs.ProfileViewBasic[] | undefined = undefined + sender: ChatBskyActorDefs.ProfileViewBasic | undefined + recipients: ChatBskyActorDefs.ProfileViewBasic[] | undefined = undefined snapshot: ConvoState | undefined constructor(params: ConvoParams) { @@ -445,7 +445,7 @@ export class Convo { throw new Error('Convo: could not find recipients in convo') } - const userIsDisabled = this.sender.chatDisabled as boolean + const userIsDisabled = Boolean(this.sender.chatDisabled) if (userIsDisabled) { this.dispatch({event: ConvoDispatchEvent.Disable}) @@ -511,8 +511,8 @@ export class Convo { private pendingFetchConvo: | Promise<{ convo: ChatBskyConvoDefs.ConvoView - sender: AppBskyActorDefs.ProfileViewBasic | undefined - recipients: AppBskyActorDefs.ProfileViewBasic[] + sender: ChatBskyActorDefs.ProfileViewBasic | undefined + recipients: ChatBskyActorDefs.ProfileViewBasic[] }> | undefined async fetchConvo() { @@ -520,8 +520,8 @@ export class Convo { this.pendingFetchConvo = new Promise<{ convo: ChatBskyConvoDefs.ConvoView - sender: AppBskyActorDefs.ProfileViewBasic | undefined - recipients: AppBskyActorDefs.ProfileViewBasic[] + sender: ChatBskyActorDefs.ProfileViewBasic | undefined + recipients: ChatBskyActorDefs.ProfileViewBasic[] }>(async (resolve, reject) => { try { const response = await networkRetry(2, () => { From 374d28d43cf49da6ba7e8e256f1f9a4c0ebc90de Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 16:21:57 -0600 Subject: [PATCH 068/142] Chat: fix log type check --- src/state/messages/convo/agent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/state/messages/convo/agent.ts b/src/state/messages/convo/agent.ts index d54288f500..ecb802b5ed 100644 --- a/src/state/messages/convo/agent.ts +++ b/src/state/messages/convo/agent.ts @@ -686,7 +686,7 @@ export class Convo { * If there's a rev, we should handle it. If there's not a rev, we don't * know what it is. */ - if (typeof ev.rev === 'string') { + if ('rev' in ev) { const isUninitialized = !this.latestRev const isNewEvent = this.latestRev && ev.rev > this.latestRev From d7d3b9ec17bb442bdada0221feab7edf47e815d2 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 16:24:08 -0600 Subject: [PATCH 069/142] Chat: construct lexically correct shape, even though it's only internal usage --- src/state/messages/convo/agent.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/state/messages/convo/agent.ts b/src/state/messages/convo/agent.ts index ecb802b5ed..1327d92b10 100644 --- a/src/state/messages/convo/agent.ts +++ b/src/state/messages/convo/agent.ts @@ -1031,7 +1031,10 @@ export class Convo { * `getItems` is only run in "active" status states, where * `this.sender` is defined */ - sender: this.sender!, + sender: { + $type: 'chat.bsky.convo.defs#messageViewSender', + did: this.sender!.did, + }, }, nextMessage: null, prevMessage: null, From 996e85721119ea8acab96c69484a1510187785cb Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 16:25:37 -0600 Subject: [PATCH 070/142] Chat: use correct profile types --- src/state/messages/convo/types.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/state/messages/convo/types.ts b/src/state/messages/convo/types.ts index 21772262ea..3692083054 100644 --- a/src/state/messages/convo/types.ts +++ b/src/state/messages/convo/types.ts @@ -1,6 +1,6 @@ import { - AppBskyActorDefs, BskyAgent, + ChatBskyActorDefs, ChatBskyConvoDefs, ChatBskyConvoSendMessage, } from '@atproto/api' @@ -168,8 +168,8 @@ export type ConvoStateReady = { items: ConvoItem[] convo: ChatBskyConvoDefs.ConvoView error: undefined - sender: AppBskyActorDefs.ProfileViewBasic - recipients: AppBskyActorDefs.ProfileViewBasic[] + sender: ChatBskyActorDefs.ProfileViewBasic + recipients: ChatBskyActorDefs.ProfileViewBasic[] isFetchingHistory: boolean deleteMessage: DeleteMessage sendMessage: SendMessage @@ -180,8 +180,8 @@ export type ConvoStateBackgrounded = { items: ConvoItem[] convo: ChatBskyConvoDefs.ConvoView error: undefined - sender: AppBskyActorDefs.ProfileViewBasic - recipients: AppBskyActorDefs.ProfileViewBasic[] + sender: ChatBskyActorDefs.ProfileViewBasic + recipients: ChatBskyActorDefs.ProfileViewBasic[] isFetchingHistory: boolean deleteMessage: DeleteMessage sendMessage: SendMessage @@ -192,8 +192,8 @@ export type ConvoStateSuspended = { items: ConvoItem[] convo: ChatBskyConvoDefs.ConvoView error: undefined - sender: AppBskyActorDefs.ProfileViewBasic - recipients: AppBskyActorDefs.ProfileViewBasic[] + sender: ChatBskyActorDefs.ProfileViewBasic + recipients: ChatBskyActorDefs.ProfileViewBasic[] isFetchingHistory: boolean deleteMessage: DeleteMessage sendMessage: SendMessage @@ -216,8 +216,8 @@ export type ConvoStateDisabled = { items: ConvoItem[] convo: ChatBskyConvoDefs.ConvoView error: undefined - sender: AppBskyActorDefs.ProfileViewBasic - recipients: AppBskyActorDefs.ProfileViewBasic[] + sender: ChatBskyActorDefs.ProfileViewBasic + recipients: ChatBskyActorDefs.ProfileViewBasic[] isFetchingHistory: boolean deleteMessage: DeleteMessage sendMessage: SendMessage From 227bef87adc6f0aca6c11f46301556afb19e5734 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 16:27:04 -0600 Subject: [PATCH 071/142] Chat: fix type check in logs --- src/state/messages/events/agent.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/state/messages/events/agent.ts b/src/state/messages/events/agent.ts index 01165256a7..dea71181be 100644 --- a/src/state/messages/events/agent.ts +++ b/src/state/messages/events/agent.ts @@ -65,10 +65,7 @@ export class MessagesEventBus { const handle = (event: MessagesEventBusEvent) => { if (event.type === 'logs' && options.convoId) { const filteredLogs = event.logs.filter(log => { - if ( - typeof log.convoId === 'string' && - log.convoId === options.convoId - ) { + if ('convoId' in log && log.convoId === options.convoId) { return log.convoId === options.convoId } return false @@ -355,7 +352,7 @@ export class MessagesEventBus { * If there's a rev, we should handle it. If there's not a rev, we don't * know what it is. */ - if (typeof ev.rev === 'string') { + if ('rev' in ev) { /* * We only care about new events */ From 085492ee66a0befa966b41a1d2696b22b8d82022 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 16:37:45 -0600 Subject: [PATCH 072/142] Starter: use correct profile types --- .../StarterPack/Wizard/WizardEditListDialog.tsx | 2 +- src/screens/StarterPack/Wizard/State.tsx | 5 ++--- src/screens/StarterPack/Wizard/index.tsx | 9 +++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/StarterPack/Wizard/WizardEditListDialog.tsx b/src/components/StarterPack/Wizard/WizardEditListDialog.tsx index b67a8d302f..5ce2988427 100644 --- a/src/components/StarterPack/Wizard/WizardEditListDialog.tsx +++ b/src/components/StarterPack/Wizard/WizardEditListDialog.tsx @@ -38,7 +38,7 @@ export function WizardEditListDialog({ state: WizardState dispatch: (action: WizardAction) => void moderationOpts: ModerationOpts - profile: AppBskyActorDefs.ProfileViewBasic + profile: AppBskyActorDefs.ProfileViewDetailed }) { const {_} = useLingui() const t = useTheme() diff --git a/src/screens/StarterPack/Wizard/State.tsx b/src/screens/StarterPack/Wizard/State.tsx index b6da56065b..2edee3f25e 100644 --- a/src/screens/StarterPack/Wizard/State.tsx +++ b/src/screens/StarterPack/Wizard/State.tsx @@ -20,7 +20,7 @@ type Action = | {type: 'SetCanNext'; canNext: boolean} | {type: 'SetName'; name: string} | {type: 'SetDescription'; description: string} - | {type: 'AddProfile'; profile: AppBskyActorDefs.ProfileViewBasic} + | {type: 'AddProfile'; profile: AppBskyActorDefs.ProfileView} | {type: 'RemoveProfile'; profileDid: string} | {type: 'AddFeed'; feed: GeneratorView} | {type: 'RemoveFeed'; feedUri: string} @@ -32,7 +32,7 @@ interface State { currentStep: Step name?: string description?: string - profiles: AppBskyActorDefs.ProfileViewBasic[] + profiles: AppBskyActorDefs.ProfileView[] feeds: GeneratorView[] processing: boolean error?: string @@ -113,7 +113,6 @@ function reducer(state: State, action: Action): State { return updatedState } -// TODO supply the initial state to this component export function Provider({ starterPack, listItems, diff --git a/src/screens/StarterPack/Wizard/index.tsx b/src/screens/StarterPack/Wizard/index.tsx index b42b753e36..99431724e0 100644 --- a/src/screens/StarterPack/Wizard/index.tsx +++ b/src/screens/StarterPack/Wizard/index.tsx @@ -54,6 +54,7 @@ import {ListMaybePlaceholder} from '#/components/Lists' import {Loader} from '#/components/Loader' import {WizardEditListDialog} from '#/components/StarterPack/Wizard/WizardEditListDialog' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' import {Provider} from './State' export function Wizard({ @@ -141,7 +142,7 @@ function WizardInner({ }: { currentStarterPack?: AppBskyGraphDefs.StarterPackView currentListItems?: AppBskyGraphDefs.ListItemView[] - profile: AppBskyActorDefs.ProfileViewBasic + profile: AppBskyActorDefs.ProfileViewDetailed moderationOpts: ModerationOpts }) { const navigation = useNavigation() @@ -363,7 +364,7 @@ function Footer({ onNext: () => void nextBtnText: string moderationOpts: ModerationOpts - profile: AppBskyActorDefs.ProfileViewBasic + profile: AppBskyActorDefs.ProfileViewDetailed }) { const {_} = useLingui() const t = useTheme() @@ -577,10 +578,10 @@ function Footer({ ) } -function getName(item: AppBskyActorDefs.ProfileViewBasic | GeneratorView) { +function getName(item: atp.profile.AnyProfileView | GeneratorView) { if (typeof item.displayName === 'string') { return enforceLen(sanitizeDisplayName(item.displayName), 28, true) - } else if (typeof item.handle === 'string') { + } else if ('handle' in item) { return enforceLen(sanitizeHandle(item.handle), 28, true) } return '' From ea4c2dea6e556bdb6db0c0d5b7d5ef72bcae0fa4 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 16:40:37 -0600 Subject: [PATCH 073/142] Starter: use correct profile types --- src/lib/generate-starterpack.ts | 6 +++--- src/state/queries/starter-packs.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/generate-starterpack.ts b/src/lib/generate-starterpack.ts index 3be338ac8a..031c7d43e9 100644 --- a/src/lib/generate-starterpack.ts +++ b/src/lib/generate-starterpack.ts @@ -24,7 +24,7 @@ export const createStarterPackList = async ({ name: string description?: string descriptionFacets?: Facet[] - profiles: AppBskyActorDefs.ProfileViewBasic[] + profiles: AppBskyActorDefs.ProfileView[] agent: BskyAgent }): Promise<{uri: string; cid: string}> => { if (profiles.length === 0) throw new Error('No profiles given') @@ -68,8 +68,8 @@ export function useGenerateStarterPackMutation({ return useMutation<{uri: string; cid: string}, Error, void>({ mutationFn: async () => { - let profile: AppBskyActorDefs.ProfileViewBasic | undefined - let profiles: AppBskyActorDefs.ProfileViewBasic[] | undefined + let profile: AppBskyActorDefs.ProfileViewDetailed | undefined + let profiles: AppBskyActorDefs.ProfileView[] | undefined await Promise.all([ (async () => { diff --git a/src/state/queries/starter-packs.ts b/src/state/queries/starter-packs.ts index 85d2fc8254..ababc350b8 100644 --- a/src/state/queries/starter-packs.ts +++ b/src/state/queries/starter-packs.ts @@ -93,7 +93,7 @@ export async function invalidateStarterPack({ interface UseCreateStarterPackMutationParams { name: string description?: string - profiles: AppBskyActorDefs.ProfileViewBasic[] + profiles: AppBskyActorDefs.ProfileView[] feeds?: AppBskyFeedDefs.GeneratorView[] } From 4299f0a43665e77566024e1b9fb3675a1107569f Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 16:43:14 -0600 Subject: [PATCH 074/142] Starter: tighten types to match lex --- src/lib/generate-starterpack.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/lib/generate-starterpack.ts b/src/lib/generate-starterpack.ts index 031c7d43e9..1c3e686cfd 100644 --- a/src/lib/generate-starterpack.ts +++ b/src/lib/generate-starterpack.ts @@ -2,8 +2,10 @@ import { AppBskyActorDefs, AppBskyGraphGetStarterPack, BskyAgent, + ComAtprotoRepoApplyWrites, Facet, } from '@atproto/api' +import {$Typed} from '@atproto/api/dist/client/util' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useMutation} from '@tanstack/react-query' @@ -136,7 +138,13 @@ export function useGenerateStarterPackMutation({ }) } -function createListItem({did, listUri}: {did: string; listUri: string}) { +function createListItem({ + did, + listUri, +}: { + did: string + listUri: string +}): $Typed { return { $type: 'com.atproto.repo.applyWrites#create', collection: 'app.bsky.graph.listitem', From 61bf9291de7329b859e6d7d726b761df683bfb1f Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 16:46:30 -0600 Subject: [PATCH 075/142] Any profile type will work in blocked-and-muted --- src/lib/moderation/blocked-and-muted.ts | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/lib/moderation/blocked-and-muted.ts b/src/lib/moderation/blocked-and-muted.ts index 18e6ef3e34..bee03fa6d3 100644 --- a/src/lib/moderation/blocked-and-muted.ts +++ b/src/lib/moderation/blocked-and-muted.ts @@ -1,17 +1,9 @@ -import {AppBskyActorDefs} from '@atproto/api' +import * as atp from '#/types/atproto' -export function isBlockedOrBlocking( - profile: - | AppBskyActorDefs.ProfileViewBasic - | AppBskyActorDefs.ProfileViewDetailed, -) { +export function isBlockedOrBlocking(profile: atp.profile.AnyProfileView) { return profile.viewer?.blockedBy || profile.viewer?.blocking } -export function isMuted( - profile: - | AppBskyActorDefs.ProfileViewBasic - | AppBskyActorDefs.ProfileViewDetailed, -) { +export function isMuted(profile: atp.profile.AnyProfileView) { return profile.viewer?.muted || profile.viewer?.mutedByList } From 2622c85bf270109d6755b25ef03d852a9b181a75 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 16:48:04 -0600 Subject: [PATCH 076/142] Use dangerous util --- src/screens/StarterPack/StarterPackScreen.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/screens/StarterPack/StarterPackScreen.tsx b/src/screens/StarterPack/StarterPackScreen.tsx index 3a3e4234f1..50ce7ba37b 100644 --- a/src/screens/StarterPack/StarterPackScreen.tsx +++ b/src/screens/StarterPack/StarterPackScreen.tsx @@ -66,6 +66,7 @@ import {ProfilesList} from '#/components/StarterPack/Main/ProfilesList' import {QrCodeDialog} from '#/components/StarterPack/QrCodeDialog' import {ShareDialog} from '#/components/StarterPack/ShareDialog' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' type StarterPackScreeProps = NativeStackScreenProps< CommonNavigatorParams, @@ -387,7 +388,12 @@ function Header({ }) } - if (!AppBskyGraphStarterpack.isRecord(record)) { + if ( + !atp.dangerousIsType( + record, + AppBskyGraphStarterpack.isRecord, + ) + ) { return null } From 9449edf07a829fe6d6be638bb6a1d5466bb408c6 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 17:10:40 -0600 Subject: [PATCH 077/142] Use dangerousIsType --- src/screens/StarterPack/StarterPackLandingScreen.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/screens/StarterPack/StarterPackLandingScreen.tsx b/src/screens/StarterPack/StarterPackLandingScreen.tsx index ec31fc21d0..919e7b5d44 100644 --- a/src/screens/StarterPack/StarterPackLandingScreen.tsx +++ b/src/screens/StarterPack/StarterPackLandingScreen.tsx @@ -38,6 +38,7 @@ import {Default as ProfileCard} from '#/components/ProfileCard' import * as Prompt from '#/components/Prompt' import {RichText} from '#/components/RichText' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' const AnimatedPressable = Animated.createAnimatedComponent(Pressable) @@ -85,7 +86,12 @@ export function LandingScreen({ } // Just for types, this cannot be hit - if (!AppBskyGraphStarterpack.isRecord(starterPack.record)) { + if ( + !atp.dangerousIsType( + starterPack.record, + AppBskyGraphStarterpack.isRecord, + ) + ) { return null } From ad71585298d88a13795c687bc76ef9a2d845d3a0 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 17:13:28 -0600 Subject: [PATCH 078/142] Update new ProfileCard to use AnyProfileView --- src/components/ProfileCard.tsx | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/components/ProfileCard.tsx b/src/components/ProfileCard.tsx index 7bec14b9cc..5b1a72fafa 100644 --- a/src/components/ProfileCard.tsx +++ b/src/components/ProfileCard.tsx @@ -1,7 +1,6 @@ import React from 'react' import {GestureResponderEvent, View} from 'react-native' import { - AppBskyActorDefs, moderateProfile, ModerationOpts, RichText as RichTextApi, @@ -25,13 +24,14 @@ import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus import {Link as InternalLink, LinkProps} from '#/components/Link' import {RichText} from '#/components/RichText' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' export function Default({ profile, moderationOpts, logContext = 'ProfileCard', }: { - profile: AppBskyActorDefs.ProfileViewDetailed + profile: atp.profile.AnyProfileView moderationOpts: ModerationOpts logContext?: 'ProfileCard' | 'StarterPackProfilesList' }) { @@ -51,7 +51,7 @@ export function Card({ moderationOpts, logContext = 'ProfileCard', }: { - profile: AppBskyActorDefs.ProfileViewDetailed + profile: atp.profile.AnyProfileView moderationOpts: ModerationOpts logContext?: 'ProfileCard' | 'StarterPackProfilesList' }) { @@ -101,7 +101,7 @@ export function Link({ style, ...rest }: { - profile: AppBskyActorDefs.ProfileViewDetailed + profile: atp.profile.AnyProfileView } & Omit) { const {_} = useLingui() return ( @@ -126,7 +126,7 @@ export function Avatar({ profile, moderationOpts, }: { - profile: AppBskyActorDefs.ProfileViewDetailed + profile: atp.profile.AnyProfileView moderationOpts: ModerationOpts }) { const moderation = moderateProfile(profile, moderationOpts) @@ -161,7 +161,7 @@ export function NameAndHandle({ profile, moderationOpts, }: { - profile: AppBskyActorDefs.ProfileViewDetailed + profile: atp.profile.AnyProfileView moderationOpts: ModerationOpts }) { const t = useTheme() @@ -224,17 +224,16 @@ export function Description({ profile: profileUnshadowed, numberOfLines = 3, }: { - profile: AppBskyActorDefs.ProfileViewDetailed + profile: atp.profile.AnyProfileView numberOfLines?: number }) { const profile = useProfileShadow(profileUnshadowed) - const {description} = profile const rt = React.useMemo(() => { - if (!description) return - const rt = new RichTextApi({text: description || ''}) + if (!('description' in profile)) return + const rt = new RichTextApi({text: profile.description || ''}) rt.detectFacetsWithoutResolution() return rt - }, [description]) + }, [profile]) if (!rt) return null if ( profile.viewer && @@ -281,7 +280,7 @@ export function DescriptionPlaceholder({ } export type FollowButtonProps = { - profile: AppBskyActorDefs.ProfileViewBasic + profile: atp.profile.AnyProfileView moderationOpts: ModerationOpts logContext: LogEvents['profile:follow']['logContext'] & LogEvents['profile:unfollow']['logContext'] From 763dd5b6e2ee9504395dfe577fe26933fd636b7f Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 17:16:10 -0600 Subject: [PATCH 079/142] Use dangerousIsType --- src/screens/Signup/index.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/screens/Signup/index.tsx b/src/screens/Signup/index.tsx index 5f406eb7ae..55367fa9e0 100644 --- a/src/screens/Signup/index.tsx +++ b/src/screens/Signup/index.tsx @@ -26,6 +26,7 @@ import {Divider} from '#/components/Divider' import {LinearGradientBackground} from '#/components/LinearGradientBackground' import {InlineLinkText} from '#/components/Link' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' export function Signup({onPressBack}: {onPressBack: () => void}) { const {_} = useLingui() @@ -95,7 +96,10 @@ export function Signup({onPressBack}: {onPressBack: () => void}) { scrollable> {showStarterPackCard && - AppBskyGraphStarterpack.isRecord(starterPack.record) ? ( + atp.dangerousIsType( + starterPack.record, + AppBskyGraphStarterpack.isRecord, + ) ? ( From 839be5f3b26e05f46b3658d6a7d1ee280c53e39c Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 17:18:06 -0600 Subject: [PATCH 080/142] Remove outdated todo --- src/state/queries/messages/actor-declaration.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/state/queries/messages/actor-declaration.ts b/src/state/queries/messages/actor-declaration.ts index 1105e2b3cb..202d7b3df7 100644 --- a/src/state/queries/messages/actor-declaration.ts +++ b/src/state/queries/messages/actor-declaration.ts @@ -69,12 +69,10 @@ export function useDeleteActorDeclaration() { return useMutation({ mutationFn: async () => { if (!currentAccount) throw new Error('Not logged in') - // TODO(sam): remove validate: false once PDSes have the new lexicon const result = await agent.api.com.atproto.repo.deleteRecord({ repo: currentAccount.did, collection: 'chat.bsky.actor.declaration', rkey: 'self', - validate: false, }) return result }, From f5530aa9fa0a4d6b2e7358e95a648325f7514a27 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 17:26:45 -0600 Subject: [PATCH 081/142] Use correct profile type --- src/screens/Profile/KnownFollowers.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/screens/Profile/KnownFollowers.tsx b/src/screens/Profile/KnownFollowers.tsx index d6dd15c698..6b22a0adde 100644 --- a/src/screens/Profile/KnownFollowers.tsx +++ b/src/screens/Profile/KnownFollowers.tsx @@ -21,7 +21,7 @@ function renderItem({ item, index, }: { - item: AppBskyActorDefs.ProfileViewBasic + item: AppBskyActorDefs.ProfileView index: number }) { return ( From db63cc17f0994f924aed17cb89527d57fe966dc0 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 17:28:03 -0600 Subject: [PATCH 082/142] Use correct profile types --- src/components/dms/MessageProfileButton.tsx | 2 +- src/components/dms/util.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/dms/MessageProfileButton.tsx b/src/components/dms/MessageProfileButton.tsx index 22936b4c06..5eac7f5c59 100644 --- a/src/components/dms/MessageProfileButton.tsx +++ b/src/components/dms/MessageProfileButton.tsx @@ -19,7 +19,7 @@ import {VerifyEmailDialog} from '../dialogs/VerifyEmailDialog' export function MessageProfileButton({ profile, }: { - profile: AppBskyActorDefs.ProfileView + profile: AppBskyActorDefs.ProfileViewDetailed }) { const {_} = useLingui() const t = useTheme() diff --git a/src/components/dms/util.ts b/src/components/dms/util.ts index 003532d0c6..92e2337a9e 100644 --- a/src/components/dms/util.ts +++ b/src/components/dms/util.ts @@ -1,6 +1,6 @@ -import {AppBskyActorDefs} from '@atproto/api' +import * as atp from '#/types/atproto' -export function canBeMessaged(profile: AppBskyActorDefs.ProfileView) { +export function canBeMessaged(profile: atp.profile.AnyProfileView) { switch (profile.associated?.chat?.allowIncoming) { case 'none': return false From c691f7b1953de106ddbd76854a7fce1de97834df Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 18:03:34 -0600 Subject: [PATCH 083/142] Tighten up types --- src/screens/Onboarding/util.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/screens/Onboarding/util.ts b/src/screens/Onboarding/util.ts index 14750f34c7..143671cb34 100644 --- a/src/screens/Onboarding/util.ts +++ b/src/screens/Onboarding/util.ts @@ -2,7 +2,9 @@ import { AppBskyGraphFollow, AppBskyGraphGetFollows, BskyAgent, + ComAtprotoRepoApplyWrites, } from '@atproto/api' +import {$Typed} from '@atproto/api/dist/client/util' import {TID} from '@atproto/common-web' import chunk from 'lodash.chunk' @@ -15,7 +17,7 @@ export async function bulkWriteFollows(agent: BskyAgent, dids: string[]) { throw new Error(`bulkWriteFollows failed: no session`) } - const followRecords: AppBskyGraphFollow.Record[] = dids.map(did => { + const followRecords: $Typed[] = dids.map(did => { return { $type: 'app.bsky.graph.follow', subject: did, @@ -23,12 +25,13 @@ export async function bulkWriteFollows(agent: BskyAgent, dids: string[]) { } }) - const followWrites = followRecords.map(r => ({ - $type: 'com.atproto.repo.applyWrites#create', - collection: 'app.bsky.graph.follow', - rkey: TID.nextStr(), - value: r, - })) + const followWrites: $Typed[] = + followRecords.map(r => ({ + $type: 'com.atproto.repo.applyWrites#create', + collection: 'app.bsky.graph.follow', + rkey: TID.nextStr(), + value: r, + })) const chunks = chunk(followWrites, 50) for (const chunk of chunks) { From 1cbbf2b2f98fecf6b420399d1632c95c79588e38 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 18:05:34 -0600 Subject: [PATCH 084/142] Use dangerousIsType --- src/screens/Onboarding/StepFinished.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/screens/Onboarding/StepFinished.tsx b/src/screens/Onboarding/StepFinished.tsx index fc0ea6a247..97c8a2f22e 100644 --- a/src/screens/Onboarding/StepFinished.tsx +++ b/src/screens/Onboarding/StepFinished.tsx @@ -43,6 +43,7 @@ import {News2_Stroke2_Corner0_Rounded as News} from '#/components/icons/News2' import {Trending2_Stroke2_Corner2_Rounded as Trending} from '#/components/icons/Trending2' import {Loader} from '#/components/Loader' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' export function StepFinished() { const {_} = useLingui() @@ -198,9 +199,14 @@ export function StepFinished() { onboardDispatch({type: 'finish'}) logEvent('onboarding:finished:nextPressed', { usedStarterPack: Boolean(starterPack), - starterPackName: AppBskyGraphStarterpack.isRecord(starterPack?.record) - ? starterPack.record.name - : undefined, + starterPackName: + starterPack && + atp.dangerousIsType( + starterPack.record, + AppBskyGraphStarterpack.isRecord, + ) + ? starterPack.record.name + : undefined, starterPackCreator: starterPack?.creator.did, starterPackUri: starterPack?.uri, profilesFollowed: listItems?.length ?? 0, From cf814ed0b99578abe75f171ded1c7de4ae508fd3 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 18:13:57 -0600 Subject: [PATCH 085/142] Chat: more type fixes --- src/components/dms/ConvoMenu.tsx | 9 +++------ src/components/dms/MessagesListBlockedFooter.tsx | 5 +++-- src/components/dms/MessagesListHeader.tsx | 11 ++++------- src/screens/Messages/Conversation.tsx | 5 +++-- src/screens/Messages/components/MessagesList.tsx | 3 ++- 5 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/components/dms/ConvoMenu.tsx b/src/components/dms/ConvoMenu.tsx index e1f8df10b8..27b796250a 100644 --- a/src/components/dms/ConvoMenu.tsx +++ b/src/components/dms/ConvoMenu.tsx @@ -1,10 +1,6 @@ import React, {useCallback} from 'react' import {Keyboard, Pressable, View} from 'react-native' -import { - AppBskyActorDefs, - ChatBskyConvoDefs, - ModerationCause, -} from '@atproto/api' +import {ChatBskyConvoDefs, ModerationCause} from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useNavigation} from '@react-navigation/native' @@ -34,6 +30,7 @@ import { import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute} from '#/components/icons/Speaker' import * as Menu from '#/components/Menu' import * as Prompt from '#/components/Prompt' +import * as atp from '#/types/atproto' import {Bubble_Stroke2_Corner2_Rounded as Bubble} from '../icons/Bubble' let ConvoMenu = ({ @@ -47,7 +44,7 @@ let ConvoMenu = ({ style, }: { convo: ChatBskyConvoDefs.ConvoView - profile: Shadow + profile: Shadow control?: Menu.MenuControlProps currentScreen: 'list' | 'conversation' showMarkAsRead?: boolean diff --git a/src/components/dms/MessagesListBlockedFooter.tsx b/src/components/dms/MessagesListBlockedFooter.tsx index ec7ba28558..f7780565d0 100644 --- a/src/components/dms/MessagesListBlockedFooter.tsx +++ b/src/components/dms/MessagesListBlockedFooter.tsx @@ -1,6 +1,6 @@ import React from 'react' import {View} from 'react-native' -import {AppBskyActorDefs, ModerationCause} from '@atproto/api' +import {ModerationCause} from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -14,6 +14,7 @@ import {BlockedByListDialog} from '#/components/dms/BlockedByListDialog' import {LeaveConvoPrompt} from '#/components/dms/LeaveConvoPrompt' import {ReportConversationPrompt} from '#/components/dms/ReportConversationPrompt' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' export function MessagesListBlockedFooter({ recipient: initialRecipient, @@ -21,7 +22,7 @@ export function MessagesListBlockedFooter({ hasMessages, blockInfo, }: { - recipient: AppBskyActorDefs.ProfileViewBasic + recipient: atp.profile.AnyProfileView convoId: string hasMessages: boolean blockInfo: { diff --git a/src/components/dms/MessagesListHeader.tsx b/src/components/dms/MessagesListHeader.tsx index acffa0c2ba..2d5d535aef 100644 --- a/src/components/dms/MessagesListHeader.tsx +++ b/src/components/dms/MessagesListHeader.tsx @@ -1,10 +1,6 @@ import React, {useCallback} from 'react' import {TouchableOpacity, View} from 'react-native' -import { - AppBskyActorDefs, - ModerationCause, - ModerationDecision, -} from '@atproto/api' +import {ModerationCause, ModerationDecision} from '@atproto/api' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -24,6 +20,7 @@ import {Bell2Off_Filled_Corner0_Rounded as BellStroke} from '#/components/icons/ import {Link} from '#/components/Link' import {PostAlerts} from '#/components/moderation/PostAlerts' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' const PFP_SIZE = isWeb ? 40 : 34 @@ -32,7 +29,7 @@ export let MessagesListHeader = ({ moderation, blockInfo, }: { - profile?: AppBskyActorDefs.ProfileViewBasic + profile?: atp.profile.AnyProfileView moderation?: ModerationDecision blockInfo?: { listBlocks: ModerationCause[] @@ -131,7 +128,7 @@ function HeaderReady({ moderation, blockInfo, }: { - profile: AppBskyActorDefs.ProfileViewBasic + profile: atp.profile.AnyProfileView moderation: ModerationDecision blockInfo: { listBlocks: ModerationCause[] diff --git a/src/screens/Messages/Conversation.tsx b/src/screens/Messages/Conversation.tsx index b8b0bfe0d3..c7c76c7ddb 100644 --- a/src/screens/Messages/Conversation.tsx +++ b/src/screens/Messages/Conversation.tsx @@ -1,6 +1,6 @@ import React, {useCallback} from 'react' import {View} from 'react-native' -import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api' +import {moderateProfile, ModerationOpts} from '@atproto/api' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useFocusEffect, useNavigation} from '@react-navigation/native' @@ -26,6 +26,7 @@ import {MessagesListHeader} from '#/components/dms/MessagesListHeader' import {Error} from '#/components/Error' import * as Layout from '#/components/Layout' import {Loader} from '#/components/Loader' +import * as atp from '#/types/atproto' type Props = NativeStackScreenProps< CommonNavigatorParams, @@ -150,7 +151,7 @@ function InnerReady({ setHasScrolled, }: { moderationOpts: ModerationOpts - recipient: AppBskyActorDefs.ProfileViewBasic + recipient: atp.profile.AnyProfileView hasScrolled: boolean setHasScrolled: React.Dispatch> }) { diff --git a/src/screens/Messages/components/MessagesList.tsx b/src/screens/Messages/components/MessagesList.tsx index 071ce1cd71..3f3e99c031 100644 --- a/src/screens/Messages/components/MessagesList.tsx +++ b/src/screens/Messages/components/MessagesList.tsx @@ -11,6 +11,7 @@ import Animated, { import {ReanimatedScrollEvent} from 'react-native-reanimated/lib/typescript/hook/commonTypes' import {useSafeAreaInsets} from 'react-native-safe-area-context' import {AppBskyEmbedRecord, AppBskyRichtextFacet, RichText} from '@atproto/api' +import {$Typed} from '@atproto/api/dist/client/util' import {clamp} from '#/lib/numbers' import {ScrollProvider} from '#/lib/ScrollContext' @@ -297,7 +298,7 @@ export function MessagesList({ // we want to remove the post link from the text, re-trim, then detect facets rt.detectFacetsWithoutResolution() - let embed: AppBskyEmbedRecord.Main | undefined + let embed: $Typed | undefined if (embedUri) { try { From 30fd3f56da042d4e22c570c8656cc51f7d8626f4 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 19:43:16 -0600 Subject: [PATCH 086/142] Remove unused file --- src/lib/embeds.ts | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 src/lib/embeds.ts diff --git a/src/lib/embeds.ts b/src/lib/embeds.ts deleted file mode 100644 index 2904f1cc36..0000000000 --- a/src/lib/embeds.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { - AppBskyEmbedRecord, - AppBskyEmbedRecordWithMedia, - AppBskyFeedDefs, -} from '@atproto/api' - -export function isEmbedByEmbedder( - embed: AppBskyFeedDefs.PostView['embed'], - did: string, -): boolean { - if (!embed) { - return false - } - if (AppBskyEmbedRecord.isViewRecord(embed.record)) { - return embed.record.author.did === did - } - if ( - AppBskyEmbedRecordWithMedia.isView(embed) && - AppBskyEmbedRecord.isViewRecord(embed.record.record) - ) { - return embed.record.record.author.did === did - } - return true -} From 6f1fab4b140756bc601ad51c3858423ce8c40ed3 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 19:46:51 -0600 Subject: [PATCH 087/142] Add a few utils --- src/lib/api/index.ts | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/lib/api/index.ts b/src/lib/api/index.ts index 75b9938fcc..1803a811ac 100644 --- a/src/lib/api/index.ts +++ b/src/lib/api/index.ts @@ -13,6 +13,7 @@ import { ComAtprotoRepoStrongRef, RichText, } from '@atproto/api' +import {$Typed} from '@atproto/api/dist/client/util' import {TID} from '@atproto/common-web' import * as dcbor from '@ipld/dag-cbor' import {t} from '@lingui/macro' @@ -74,7 +75,7 @@ export async function post( } const did = agent.assertDid - const writes: ComAtprotoRepoApplyWrites.Create[] = [] + const writes: $Typed[] = [] const uris: string[] = [] let now = new Date() @@ -91,7 +92,7 @@ export async function post( draft, opts.onStateChange, ) - let labels: ComAtprotoLabelDefs.SelfLabels | undefined + let labels: $Typed | undefined if (draft.labels.length) { labels = { $type: 'com.atproto.label.defs#selfLabels', @@ -225,11 +226,11 @@ async function resolveEmbed( draft: PostDraft, onStateChange: ((state: string) => void) | undefined, ): Promise< - | AppBskyEmbedImages.Main - | AppBskyEmbedVideo.Main - | AppBskyEmbedExternal.Main - | AppBskyEmbedRecord.Main - | AppBskyEmbedRecordWithMedia.Main + | $Typed + | $Typed + | $Typed + | $Typed + | $Typed | undefined > { if (draft.embed.quote) { @@ -283,9 +284,9 @@ async function resolveMedia( embedDraft: EmbedDraft, onStateChange: ((state: string) => void) | undefined, ): Promise< - | AppBskyEmbedExternal.Main - | AppBskyEmbedImages.Main - | AppBskyEmbedVideo.Main + | $Typed + | $Typed + | $Typed | undefined > { if (embedDraft.media?.type === 'images') { From d35df902f30410fa5c940df17969d5882c64fc50 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 19:47:30 -0600 Subject: [PATCH 088/142] Remove unused file --- src/lib/api/hack-add-deleted-embed.ts | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 src/lib/api/hack-add-deleted-embed.ts diff --git a/src/lib/api/hack-add-deleted-embed.ts b/src/lib/api/hack-add-deleted-embed.ts deleted file mode 100644 index 59aad21a21..0000000000 --- a/src/lib/api/hack-add-deleted-embed.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { - AppBskyFeedDefs, - AppBskyFeedPost, - ComAtprotoRepoStrongRef, -} from '@atproto/api' - -/** - * HACK - * The server doesnt seem to be correctly giving the notFound view yet - * so I'm adding it manually for now - * -prf - */ -export function hackAddDeletedEmbed(post: AppBskyFeedDefs.PostView) { - const record = post.record as AppBskyFeedPost.Record - if (record.embed?.$type === 'app.bsky.embed.record' && !post.embed) { - post.embed = { - $type: 'app.bsky.embed.record#view', - record: { - $type: 'app.bsky.embed.record#viewNotFound', - uri: (record.embed.record as ComAtprotoRepoStrongRef.Main).uri, - }, - } - } -} From 3047644f06c385bf24617e228563f880327c9613 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 19:49:12 -0600 Subject: [PATCH 089/142] Ignore feedPost.__source --- src/lib/api/feed/merge.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/api/feed/merge.ts b/src/lib/api/feed/merge.ts index 35c3440553..7f8c1c2755 100644 --- a/src/lib/api/feed/merge.ts +++ b/src/lib/api/feed/merge.ts @@ -311,6 +311,7 @@ class MergeFeedSource_Custom extends MergeFeedSource { ) // attach source info for (const post of res.data.feed) { + // @ts-ignore post.__source = this.sourceInfo } return res From 5d15b250c43568b2c149396571cfbe18aff2a6b9 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 19:58:50 -0600 Subject: [PATCH 090/142] Clean up types, leave validation in critical path --- src/lib/api/feed-manip.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/lib/api/feed-manip.ts b/src/lib/api/feed-manip.ts index 0eca8b1655..3867e75c04 100644 --- a/src/lib/api/feed-manip.ts +++ b/src/lib/api/feed-manip.ts @@ -55,16 +55,15 @@ export class FeedViewPostsSlice { } this._feedPost = feedPost this._reactKey = `slice-${post.uri}-${ - feedPost.reason?.indexedAt || post.indexedAt + feedPost.reason && 'indexedAt' in feedPost.reason + ? feedPost.reason.indexedAt + : post.indexedAt }` if (feedPost.post.uri === FALLBACK_MARKER_POST.post.uri) { this.isFallbackMarker = true return } - if ( - !AppBskyFeedPost.isRecord(post.record) || - !AppBskyFeedPost.validateRecord(post.record).success - ) { + if (!AppBskyFeedPost.isValidRecord(post.record)) { return } const parent = reply?.parent @@ -94,8 +93,7 @@ export class FeedViewPostsSlice { } if ( !AppBskyFeedDefs.isPostView(parent) || - !AppBskyFeedPost.isRecord(parent.record) || - !AppBskyFeedPost.validateRecord(parent.record).success + !AppBskyFeedPost.isValidRecord(parent.record) ) { this.isOrphan = true return @@ -136,8 +134,7 @@ export class FeedViewPostsSlice { } if ( !AppBskyFeedDefs.isPostView(root) || - !AppBskyFeedPost.isRecord(root.record) || - !AppBskyFeedPost.validateRecord(root.record).success + !AppBskyFeedPost.isValidRecord(root.record) ) { this.isOrphan = true return From 4020584d20a61e767bddd80fc6b26c645586cdce Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 19:59:00 -0600 Subject: [PATCH 091/142] Use dangerousIstype --- src/components/WhoCanReply.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/WhoCanReply.tsx b/src/components/WhoCanReply.tsx index ab6ef8293c..a992aeccce 100644 --- a/src/components/WhoCanReply.tsx +++ b/src/components/WhoCanReply.tsx @@ -29,6 +29,7 @@ import {Earth_Stroke2_Corner0_Rounded as Earth} from '#/components/icons/Globe' import {Group3_Stroke2_Corner0_Rounded as Group} from '#/components/icons/Group' import {InlineLinkText} from '#/components/Link' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' import {PencilLine_Stroke2_Corner0_Rounded as PencilLine} from './icons/Pencil' interface WhoCanReplyProps { @@ -48,7 +49,10 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) { * unexpectedly, we should check to make sure it's for sure the root URI. */ const rootUri = - AppBskyFeedPost.isRecord(post.record) && post.record.reply?.root + atp.dangerousIsType( + post.record, + AppBskyFeedPost.isRecord, + ) && post.record.reply?.root ? post.record.reply.root.uri : post.uri const settings = React.useMemo(() => { From 7dea8b07cf72157696b469e5696dd809a0a485ff Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 20:07:01 -0600 Subject: [PATCH 092/142] Use ANyProfileView --- src/components/hooks/useFollowMethods.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/hooks/useFollowMethods.ts b/src/components/hooks/useFollowMethods.ts index d67c3690f9..ffce60ea2c 100644 --- a/src/components/hooks/useFollowMethods.ts +++ b/src/components/hooks/useFollowMethods.ts @@ -1,5 +1,4 @@ import React from 'react' -import {AppBskyActorDefs} from '@atproto/api' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -9,12 +8,13 @@ import {Shadow} from '#/state/cache/types' import {useProfileFollowMutationQueue} from '#/state/queries/profile' import {useRequireAuth} from '#/state/session' import * as Toast from '#/view/com/util/Toast' +import * as atp from '#/types/atproto' export function useFollowMethods({ profile, logContext, }: { - profile: Shadow + profile: Shadow logContext: LogEvents['profile:follow']['logContext'] & LogEvents['profile:unfollow']['logContext'] }) { From 9773355b15e8b6eabbb45f27886b939087b122a3 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 20:08:08 -0600 Subject: [PATCH 093/142] Use isValidRecord --- src/components/StarterPack/QrCodeDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/StarterPack/QrCodeDialog.tsx b/src/components/StarterPack/QrCodeDialog.tsx index 2feea0973a..79de3bfba5 100644 --- a/src/components/StarterPack/QrCodeDialog.tsx +++ b/src/components/StarterPack/QrCodeDialog.tsx @@ -77,7 +77,7 @@ export function QrCodeDialog({ } else { setIsProcessing(true) - if (!AppBskyGraphStarterpack.isRecord(starterPack.record)) { + if (!AppBskyGraphStarterpack.isValidRecord(starterPack.record)) { return } From f6488dd2f7df12dfc0f8827ee88a4651a1df8be8 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Jan 2025 20:11:16 -0600 Subject: [PATCH 094/142] Use dangerousIsType --- src/components/StarterPack/QrCode.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/StarterPack/QrCode.tsx b/src/components/StarterPack/QrCode.tsx index 515a9059ab..a6e3208fff 100644 --- a/src/components/StarterPack/QrCode.tsx +++ b/src/components/StarterPack/QrCode.tsx @@ -13,6 +13,7 @@ import {useTheme} from '#/alf' import {atoms as a} from '#/alf' import {LinearGradientBackground} from '#/components/LinearGradientBackground' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' const LazyViewShot = React.lazy( // @ts-expect-error dynamic import @@ -30,7 +31,12 @@ export const QrCode = React.forwardRef(function QrCode( ) { const {record} = starterPack - if (!AppBskyGraphStarterpack.isRecord(record)) { + if ( + !atp.dangerousIsType( + record, + AppBskyGraphStarterpack.isRecord, + ) + ) { return null } From e7b17b59dcf7626828c57ee2f80d16aa6b6238bd Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 8 Jan 2025 09:05:55 -0600 Subject: [PATCH 095/142] Fix types in ListCard --- src/components/ListCard.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ListCard.tsx b/src/components/ListCard.tsx index ed5838fb04..13fc4e222b 100644 --- a/src/components/ListCard.tsx +++ b/src/components/ListCard.tsx @@ -1,7 +1,6 @@ import React from 'react' import {View} from 'react-native' import { - AppBskyActorDefs, AppBskyGraphDefs, AtUri, moderateUserList, @@ -26,6 +25,7 @@ import { import {Link as InternalLink, LinkProps} from '#/components/Link' import * as Hider from '#/components/moderation/Hider' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' /* * This component is based on `FeedCard` and is tightly coupled with that @@ -107,7 +107,7 @@ export function TitleAndByline({ modUi, }: { title: string - creator?: AppBskyActorDefs.ProfileViewBasic + creator?: atp.profile.AnyProfileView purpose?: AppBskyGraphDefs.ListView['purpose'] modUi?: ModerationUI }) { From a9c8c77deb2691a16be72e1489146152484d5642 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 8 Jan 2025 09:07:25 -0600 Subject: [PATCH 096/142] Fix FeedInterstitials types --- src/components/FeedInterstitials.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/FeedInterstitials.tsx b/src/components/FeedInterstitials.tsx index ec224eeae0..c1a4474407 100644 --- a/src/components/FeedInterstitials.tsx +++ b/src/components/FeedInterstitials.tsx @@ -1,7 +1,7 @@ import React from 'react' import {View} from 'react-native' import {ScrollView} from 'react-native-gesture-handler' -import {AppBskyActorDefs, AppBskyFeedDefs, AtUri} from '@atproto/api' +import {AppBskyFeedDefs, AtUri} from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useNavigation} from '@react-navigation/native' @@ -26,6 +26,7 @@ import {PersonPlus_Stroke2_Corner0_Rounded as Person} from '#/components/icons/P import {InlineLinkText} from '#/components/Link' import * as ProfileCard from '#/components/ProfileCard' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' import {ProgressGuideList} from './ProgressGuide/List' const MOBILE_CARD_WIDTH = 300 @@ -225,7 +226,7 @@ export function ProfileGrid({ viewContext = 'feed', }: { isSuggestionsLoading: boolean - profiles: AppBskyActorDefs.ProfileViewDetailed[] + profiles: atp.profile.AnyProfileView[] error: Error | null viewContext: 'profile' | 'feed' }) { From d7c45f00fa8fde06bebe42e9ec498d78840c11a0 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 8 Jan 2025 09:08:13 -0600 Subject: [PATCH 097/142] Fix types in FeedCard --- src/components/FeedCard.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/FeedCard.tsx b/src/components/FeedCard.tsx index de94d7e196..cd8dba4aca 100644 --- a/src/components/FeedCard.tsx +++ b/src/components/FeedCard.tsx @@ -1,7 +1,6 @@ import React from 'react' import {GestureResponderEvent, View} from 'react-native' import { - AppBskyActorDefs, AppBskyFeedDefs, AppBskyGraphDefs, AtUri, @@ -32,6 +31,7 @@ import {Loader} from '#/components/Loader' import * as Prompt from '#/components/Prompt' import {RichText, RichTextProps} from '#/components/RichText' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' type Props = { view: AppBskyFeedDefs.GeneratorView @@ -115,7 +115,7 @@ export function TitleAndByline({ creator, }: { title: string - creator?: AppBskyActorDefs.ProfileViewBasic + creator?: atp.profile.AnyProfileView }) { const t = useTheme() From 54ecbd743b966542fd73f6bb0a28df2280739bca Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 8 Jan 2025 09:10:31 -0600 Subject: [PATCH 098/142] Fix types in dms ReportDialog --- src/components/dms/ReportDialog.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/components/dms/ReportDialog.tsx b/src/components/dms/ReportDialog.tsx index 06d69ff4be..f9b7d68732 100644 --- a/src/components/dms/ReportDialog.tsx +++ b/src/components/dms/ReportDialog.tsx @@ -5,6 +5,7 @@ import { ComAtprotoModerationCreateReport, RichText as RichTextAPI, } from '@atproto/api' +import {$Typed} from '@atproto/api/dist/client/util' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useMutation} from '@tanstack/react-query' @@ -109,15 +110,16 @@ function SubmitStep({ mutationFn: async () => { if (params.type === 'convoMessage') { const {convoId, message} = params + const subject: $Typed = { + $type: 'chat.bsky.convo.defs#messageRef', + messageId: message.id, + convoId, + did: message.sender.did, + } const report = { reasonType: reportOption.reason, - subject: { - $type: 'chat.bsky.convo.defs#messageRef', - messageId: message.id, - convoId, - did: message.sender.did, - } satisfies ChatBskyConvoDefs.MessageRef, + subject, reason: details, } satisfies ComAtprotoModerationCreateReport.InputSchema From 696e3f93db548f6fdea36dfbbcad0fe1e05ff754 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 8 Jan 2025 09:12:44 -0600 Subject: [PATCH 099/142] Fix types in SearchablePeopleList --- src/components/dms/dialogs/SearchablePeopleList.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/dms/dialogs/SearchablePeopleList.tsx b/src/components/dms/dialogs/SearchablePeopleList.tsx index 50090cbcbb..52ed297766 100644 --- a/src/components/dms/dialogs/SearchablePeopleList.tsx +++ b/src/components/dms/dialogs/SearchablePeopleList.tsx @@ -6,7 +6,7 @@ import React, { useState, } from 'react' import {TextInput, View} from 'react-native' -import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api' +import {moderateProfile, ModerationOpts} from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -28,13 +28,14 @@ import {useInteractionState} from '#/components/hooks/useInteractionState' import {MagnifyingGlass2_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass2' import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' type Item = | { type: 'profile' key: string enabled: boolean - profile: AppBskyActorDefs.ProfileView + profile: atp.profile.AnyProfileView } | { type: 'empty' @@ -330,7 +331,7 @@ function ProfileCard({ onPress, }: { enabled: boolean - profile: AppBskyActorDefs.ProfileView + profile: atp.profile.AnyProfileView moderationOpts: ModerationOpts onPress: (did: string) => void }) { From 56413080998e32da298bdc39db535a38b1931422 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 8 Jan 2025 09:18:05 -0600 Subject: [PATCH 100/142] Fix bad type in composer opts --- src/state/shell/composer/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/state/shell/composer/index.tsx b/src/state/shell/composer/index.tsx index f1ea41c640..33634c0477 100644 --- a/src/state/shell/composer/index.tsx +++ b/src/state/shell/composer/index.tsx @@ -1,7 +1,6 @@ import React from 'react' import { AppBskyActorDefs, - AppBskyEmbedRecord, AppBskyFeedDefs, ModerationDecision, } from '@atproto/api' @@ -21,7 +20,7 @@ export interface ComposerOptsPostRef { cid: string text: string author: AppBskyActorDefs.ProfileViewBasic - embed?: AppBskyEmbedRecord.ViewRecord['embed'] + embed?: AppBskyFeedDefs.PostView['embed'] moderation?: ModerationDecision } From 18e329c2af9f808223b65316c01ebdfcfdb67512 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 8 Jan 2025 09:24:33 -0600 Subject: [PATCH 101/142] Starter: ok these need to be loose too --- src/components/StarterPack/Wizard/WizardListCard.tsx | 3 ++- src/lib/generate-starterpack.ts | 3 ++- src/screens/StarterPack/Wizard/State.tsx | 11 ++++------- src/screens/StarterPack/Wizard/StepProfiles.tsx | 3 ++- src/state/queries/starter-packs.ts | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/components/StarterPack/Wizard/WizardListCard.tsx b/src/components/StarterPack/Wizard/WizardListCard.tsx index 75d2bff60e..77eb8365ae 100644 --- a/src/components/StarterPack/Wizard/WizardListCard.tsx +++ b/src/components/StarterPack/Wizard/WizardListCard.tsx @@ -22,6 +22,7 @@ import {Button, ButtonText} from '#/components/Button' import * as Toggle from '#/components/forms/Toggle' import {Checkbox} from '#/components/forms/Toggle' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' function WizardListCard({ type, @@ -123,7 +124,7 @@ export function WizardProfileCard({ btnType: 'checkbox' | 'remove' state: WizardState dispatch: (action: WizardAction) => void - profile: AppBskyActorDefs.ProfileViewBasic + profile: atp.profile.AnyProfileView moderationOpts: ModerationOpts }) { const {currentAccount} = useSession() diff --git a/src/lib/generate-starterpack.ts b/src/lib/generate-starterpack.ts index 1c3e686cfd..f31485cef1 100644 --- a/src/lib/generate-starterpack.ts +++ b/src/lib/generate-starterpack.ts @@ -15,6 +15,7 @@ import {sanitizeDisplayName} from '#/lib/strings/display-names' import {sanitizeHandle} from '#/lib/strings/handles' import {enforceLen} from '#/lib/strings/helpers' import {useAgent} from '#/state/session' +import * as atp from '#/types/atproto' export const createStarterPackList = async ({ name, @@ -26,7 +27,7 @@ export const createStarterPackList = async ({ name: string description?: string descriptionFacets?: Facet[] - profiles: AppBskyActorDefs.ProfileView[] + profiles: atp.profile.AnyProfileView[] agent: BskyAgent }): Promise<{uri: string; cid: string}> => { if (profiles.length === 0) throw new Error('No profiles given') diff --git a/src/screens/StarterPack/Wizard/State.tsx b/src/screens/StarterPack/Wizard/State.tsx index 2edee3f25e..652e0afab3 100644 --- a/src/screens/StarterPack/Wizard/State.tsx +++ b/src/screens/StarterPack/Wizard/State.tsx @@ -1,15 +1,12 @@ import React from 'react' -import { - AppBskyActorDefs, - AppBskyGraphDefs, - AppBskyGraphStarterpack, -} from '@atproto/api' +import {AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api' import {GeneratorView} from '@atproto/api/dist/client/types/app/bsky/feed/defs' import {msg} from '@lingui/macro' import {STARTER_PACK_MAX_SIZE} from '#/lib/constants' import {useSession} from '#/state/session' import * as Toast from '#/view/com/util/Toast' +import * as atp from '#/types/atproto' const steps = ['Details', 'Profiles', 'Feeds'] as const type Step = (typeof steps)[number] @@ -20,7 +17,7 @@ type Action = | {type: 'SetCanNext'; canNext: boolean} | {type: 'SetName'; name: string} | {type: 'SetDescription'; description: string} - | {type: 'AddProfile'; profile: AppBskyActorDefs.ProfileView} + | {type: 'AddProfile'; profile: atp.profile.AnyProfileView} | {type: 'RemoveProfile'; profileDid: string} | {type: 'AddFeed'; feed: GeneratorView} | {type: 'RemoveFeed'; feedUri: string} @@ -32,7 +29,7 @@ interface State { currentStep: Step name?: string description?: string - profiles: AppBskyActorDefs.ProfileView[] + profiles: atp.profile.AnyProfileView[] feeds: GeneratorView[] processing: boolean error?: string diff --git a/src/screens/StarterPack/Wizard/StepProfiles.tsx b/src/screens/StarterPack/Wizard/StepProfiles.tsx index e13febc75d..0c0cafa2f9 100644 --- a/src/screens/StarterPack/Wizard/StepProfiles.tsx +++ b/src/screens/StarterPack/Wizard/StepProfiles.tsx @@ -16,6 +16,7 @@ import {Loader} from '#/components/Loader' import {ScreenTransition} from '#/components/StarterPack/Wizard/ScreenTransition' import {WizardProfileCard} from '#/components/StarterPack/Wizard/WizardListCard' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' function keyExtractor(item: AppBskyActorDefs.ProfileViewBasic) { return item?.did ?? '' @@ -50,7 +51,7 @@ export function StepProfiles({ const renderItem = ({ item, - }: ListRenderItemInfo) => { + }: ListRenderItemInfo) => { return ( Date: Wed, 8 Jan 2025 09:27:30 -0600 Subject: [PATCH 102/142] Clarify docs Co-authored-by: Matthieu Sieben --- src/types/atproto/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/types/atproto/index.ts b/src/types/atproto/index.ts index ee24ab1e3d..5792770a08 100644 --- a/src/types/atproto/index.ts +++ b/src/types/atproto/index.ts @@ -13,7 +13,8 @@ export * as starterPack from '#/types/atproto/starterPack' * ```ts * import * as atp from '#/types/atproto' * - * if (atp.dangerousIsType(node.post.record, AppBskyFeedPost.isRecord)) { + * if (atp.dangerousIsType(item, AppBskyFeedPost.isRecord)) { + * // `item` has type `$Typed` here * } * ``` */ From 976e8300274537d85e4b698e81491aa98594823a Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 8 Jan 2025 09:28:19 -0600 Subject: [PATCH 103/142] Less code Co-authored-by: Matthieu Sieben --- src/types/atproto/post.ts | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/types/atproto/post.ts b/src/types/atproto/post.ts index ffd6eb47d2..993235237c 100644 --- a/src/types/atproto/post.ts +++ b/src/types/atproto/post.ts @@ -61,47 +61,47 @@ export type View = } export function parseEmbedView( - view: AppBskyEmbedRecord.View, + { record }: AppBskyEmbedRecord.View, ): View | undefined { - if (AppBskyEmbedRecord.isViewRecord(view.record)) { + if (AppBskyEmbedRecord.isViewRecord(record)) { return { type: 'post', - view: view.record, + view: record, } - } else if (AppBskyEmbedRecord.isViewNotFound(view.record)) { + } else if (AppBskyEmbedRecord.isViewNotFound(record)) { return { type: 'post_not_found', - view: view.record, + view: record, } - } else if (AppBskyEmbedRecord.isViewBlocked(view.record)) { + } else if (AppBskyEmbedRecord.isViewBlocked(record)) { return { type: 'post_blocked', - view: view.record, + view: record, } - } else if (AppBskyEmbedRecord.isViewDetached(view.record)) { + } else if (AppBskyEmbedRecord.isViewDetached(record)) { return { type: 'post_detached', - view: view.record, + view: record, } - } else if (AppBskyFeedDefs.isGeneratorView(view.record)) { + } else if (AppBskyFeedDefs.isGeneratorView(record)) { return { type: 'feed', - view: view.record, + view: record, } - } else if (AppBskyGraphDefs.isListView(view.record)) { + } else if (AppBskyGraphDefs.isListView(record)) { return { type: 'list', - view: view.record, + view: record, } - } else if (AppBskyLabelerDefs.isLabelerView(view.record)) { + } else if (AppBskyLabelerDefs.isLabelerView(record)) { return { type: 'labeler', - view: view.record, + view: record, } - } else if (AppBskyGraphDefs.isStarterPackViewBasic(view.record)) { + } else if (AppBskyGraphDefs.isStarterPackViewBasic(record)) { return { type: 'starter_pack', - view: view.record, + view: record, } } } From 0d28fd5834745689c5e0e368cd490a7d5bb0eb66 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 8 Jan 2025 09:29:27 -0600 Subject: [PATCH 104/142] Use package exports Co-authored-by: Matthieu Sieben --- src/types/atproto/starterPack.ts | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/types/atproto/starterPack.ts b/src/types/atproto/starterPack.ts index 513b4750bd..0064e16bc6 100644 --- a/src/types/atproto/starterPack.ts +++ b/src/types/atproto/starterPack.ts @@ -1,17 +1,7 @@ import {AppBskyGraphDefs} from '@atproto/api' -export { - /** - * Renamed to clarify source of this util, but directly aliases the original. - * {@link AppBskyGraphDefs.isStarterPackViewBasic} - */ - isStarterPackViewBasic as isBasicView, - /** - * Renamed to clarify source of this util, but directly aliases the original. - * {@link AppBskyGraphDefs.isStarterPackView} - */ - isStarterPackView as isView, -} from '@atproto/api/dist/client/types/app/bsky/graph/defs' +export const isBasicView = AppBskyGraphDefs.isStarterPackViewBasic +export const isView = AppBskyGraphDefs.isStarterPackView /** * Matches any starter pack view exported by our SDK From 2f0dd92466506dd9d782b2d9492a0eb8cf1b6d98 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 8 Jan 2025 09:31:22 -0600 Subject: [PATCH 105/142] Use package exports --- src/types/atproto/profile.ts | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/src/types/atproto/profile.ts b/src/types/atproto/profile.ts index 7c0aae287e..9a36c8cd9b 100644 --- a/src/types/atproto/profile.ts +++ b/src/types/atproto/profile.ts @@ -1,22 +1,8 @@ import {AppBskyActorDefs, ChatBskyActorDefs} 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' +export const isBasicView = AppBskyActorDefs.isProfileViewBasic +export const isDetailedView = AppBskyActorDefs.isProfileViewDetailed +export const isView = AppBskyActorDefs.isProfileView /** * Matches any profile view exported by our SDK From 40db806fe58e0db7ce9f7f75a60a43afe67fbb20 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 8 Jan 2025 09:35:40 -0600 Subject: [PATCH 106/142] Bump sdk, update $Typed imports --- package.json | 2 +- src/components/dms/ReportDialog.tsx | 2 +- src/lib/api/index.ts | 2 +- src/lib/generate-starterpack.ts | 2 +- .../Messages/components/MessagesList.tsx | 8 +++- src/screens/Onboarding/util.ts | 2 +- src/screens/Settings/components/PwiOptOut.tsx | 3 +- src/state/queries/list.ts | 2 +- src/state/queries/postgate/util.ts | 2 +- yarn.lock | 43 ++++++++++++++++--- 10 files changed, 50 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index ec4595eb4b..8d2d4c8571 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "icons:optimize": "svgo -f ./assets/icons" }, "dependencies": { - "@atproto/api": "0.14.0-next.1", + "@atproto/api": "0.14.0-next.2", "@braintree/sanitize-url": "^6.0.2", "@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet", "@emoji-mart/react": "^1.1.1", diff --git a/src/components/dms/ReportDialog.tsx b/src/components/dms/ReportDialog.tsx index f9b7d68732..1ca14c10fd 100644 --- a/src/components/dms/ReportDialog.tsx +++ b/src/components/dms/ReportDialog.tsx @@ -1,11 +1,11 @@ import React, {memo, useMemo, useState} from 'react' import {View} from 'react-native' import { + $Typed, ChatBskyConvoDefs, ComAtprotoModerationCreateReport, RichText as RichTextAPI, } from '@atproto/api' -import {$Typed} from '@atproto/api/dist/client/util' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useMutation} from '@tanstack/react-query' diff --git a/src/lib/api/index.ts b/src/lib/api/index.ts index 1803a811ac..6c473b19e3 100644 --- a/src/lib/api/index.ts +++ b/src/lib/api/index.ts @@ -1,4 +1,5 @@ import { + $Typed, AppBskyEmbedExternal, AppBskyEmbedImages, AppBskyEmbedRecord, @@ -13,7 +14,6 @@ import { ComAtprotoRepoStrongRef, RichText, } from '@atproto/api' -import {$Typed} from '@atproto/api/dist/client/util' import {TID} from '@atproto/common-web' import * as dcbor from '@ipld/dag-cbor' import {t} from '@lingui/macro' diff --git a/src/lib/generate-starterpack.ts b/src/lib/generate-starterpack.ts index f31485cef1..5137983c43 100644 --- a/src/lib/generate-starterpack.ts +++ b/src/lib/generate-starterpack.ts @@ -1,11 +1,11 @@ import { + $Typed, AppBskyActorDefs, AppBskyGraphGetStarterPack, BskyAgent, ComAtprotoRepoApplyWrites, Facet, } from '@atproto/api' -import {$Typed} from '@atproto/api/dist/client/util' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useMutation} from '@tanstack/react-query' diff --git a/src/screens/Messages/components/MessagesList.tsx b/src/screens/Messages/components/MessagesList.tsx index 3f3e99c031..10a2b1d378 100644 --- a/src/screens/Messages/components/MessagesList.tsx +++ b/src/screens/Messages/components/MessagesList.tsx @@ -10,8 +10,12 @@ import Animated, { } from 'react-native-reanimated' import {ReanimatedScrollEvent} from 'react-native-reanimated/lib/typescript/hook/commonTypes' import {useSafeAreaInsets} from 'react-native-safe-area-context' -import {AppBskyEmbedRecord, AppBskyRichtextFacet, RichText} from '@atproto/api' -import {$Typed} from '@atproto/api/dist/client/util' +import { + $Typed, + AppBskyEmbedRecord, + AppBskyRichtextFacet, + RichText, +} from '@atproto/api' import {clamp} from '#/lib/numbers' import {ScrollProvider} from '#/lib/ScrollContext' diff --git a/src/screens/Onboarding/util.ts b/src/screens/Onboarding/util.ts index 143671cb34..d14c9562e6 100644 --- a/src/screens/Onboarding/util.ts +++ b/src/screens/Onboarding/util.ts @@ -1,10 +1,10 @@ import { + $Typed, AppBskyGraphFollow, AppBskyGraphGetFollows, BskyAgent, ComAtprotoRepoApplyWrites, } from '@atproto/api' -import {$Typed} from '@atproto/api/dist/client/util' import {TID} from '@atproto/common-web' import chunk from 'lodash.chunk' diff --git a/src/screens/Settings/components/PwiOptOut.tsx b/src/screens/Settings/components/PwiOptOut.tsx index 3d236e906e..4596f6cda6 100644 --- a/src/screens/Settings/components/PwiOptOut.tsx +++ b/src/screens/Settings/components/PwiOptOut.tsx @@ -1,7 +1,6 @@ import React from 'react' import {View} from 'react-native' -import {ComAtprotoLabelDefs} from '@atproto/api' -import {$Typed} from '@atproto/api/dist/client/util' +import {$Typed,ComAtprotoLabelDefs} from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' diff --git a/src/state/queries/list.ts b/src/state/queries/list.ts index f2bcaf3dc7..7aec4bc669 100644 --- a/src/state/queries/list.ts +++ b/src/state/queries/list.ts @@ -1,5 +1,6 @@ import {Image as RNImage} from 'react-native-image-crop-picker' import { + $Typed, AppBskyGraphDefs, AppBskyGraphGetList, AppBskyGraphList, @@ -8,7 +9,6 @@ import { ComAtprotoRepoApplyWrites, Facet, } from '@atproto/api' -import {$Typed} from '@atproto/api/dist/client/util' import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query' import chunk from 'lodash.chunk' diff --git a/src/state/queries/postgate/util.ts b/src/state/queries/postgate/util.ts index d7c0d1b7d7..c1955cc74f 100644 --- a/src/state/queries/postgate/util.ts +++ b/src/state/queries/postgate/util.ts @@ -1,11 +1,11 @@ import { + $Typed, AppBskyEmbedRecord, AppBskyEmbedRecordWithMedia, AppBskyFeedDefs, AppBskyFeedPostgate, AtUri, } from '@atproto/api' -import {$Typed} from '@atproto/api/dist/client/util' export const POSTGATE_COLLECTION = 'app.bsky.feed.postgate' diff --git a/yarn.lock b/yarn.lock index 992ec8c621..285f9de286 100644 --- a/yarn.lock +++ b/yarn.lock @@ -58,15 +58,15 @@ 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.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== +"@atproto/api@0.14.0-next.2": + version "0.14.0-next.2" + resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.14.0-next.2.tgz#c42313217dc5cbbd81438706018963d4232a4ba6" + integrity sha512-1FADZQAklDozrGDxrb6ydkrlBBES4sKP7wJZTtwzqb1bSUOqRD8vjuvVvklt2ahhAQvslsBUC1wBrMa7VGS6hA== dependencies: - "@atproto/common-web" "^0.3.1" - "@atproto/lexicon" "^0.4.4" + "@atproto/common-web" "^0.3.2" + "@atproto/lexicon" "^0.4.5" "@atproto/syntax" "^0.3.1" - "@atproto/xrpc" "^0.6.5" + "@atproto/xrpc" "^0.6.6" await-lock "^2.2.2" multiformats "^9.9.0" tlds "^1.234.0" @@ -169,6 +169,16 @@ uint8arrays "3.0.0" zod "^3.23.8" +"@atproto/common-web@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@atproto/common-web/-/common-web-0.3.2.tgz#4cf78ad4d24fed801882f3d35afc39bceccdff51" + integrity sha512-Vx0JtL1/CssJbFAb0UOdvTrkbUautsDfHNOXNTcX2vyPIxH9xOameSqLLunM1hZnOQbJwyjmQCt6TV+bhnanDg== + dependencies: + graphemer "^1.4.0" + multiformats "^9.9.0" + uint8arrays "3.0.0" + zod "^3.23.8" + "@atproto/common@0.1.0": version "0.1.0" resolved "https://registry.yarnpkg.com/@atproto/common/-/common-0.1.0.tgz#4216a8fef5b985ab62ac21252a0f8ca0f4a0f210" @@ -283,6 +293,17 @@ multiformats "^9.9.0" zod "^3.23.8" +"@atproto/lexicon@^0.4.5": + version "0.4.5" + resolved "https://registry.yarnpkg.com/@atproto/lexicon/-/lexicon-0.4.5.tgz#4fcf3731193c674286e9e8d677bbab5dd530b817" + integrity sha512-fljWqMGKn+XWtTprBcS3F1hGBREnQYh6qYHv2sjENucc7REms1gtmZXSerB9N6pVeHVNOnXiILdukeAcic5OEw== + dependencies: + "@atproto/common-web" "^0.3.2" + "@atproto/syntax" "^0.3.1" + iso-datestring-validator "^2.2.2" + multiformats "^9.9.0" + zod "^3.23.8" + "@atproto/oauth-provider@^0.2.10": version "0.2.10" resolved "https://registry.yarnpkg.com/@atproto/oauth-provider/-/oauth-provider-0.2.10.tgz#f9820d7f82c33d3b74e81a75873f50e1e654b901" @@ -452,6 +473,14 @@ "@atproto/lexicon" "^0.4.4" zod "^3.23.8" +"@atproto/xrpc@^0.6.6": + version "0.6.6" + resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.6.6.tgz#28f58270ef4a8056f7f718bd52512e74bcd3702f" + integrity sha512-umXEYVMo9/pyIBoKmIAIi64RXDW9tSXY+wqztlQ6I2GZtjLfNZqmAWU+wADk3SxUe54mvjxxGyA4TtyGtDMfhA== + dependencies: + "@atproto/lexicon" "^0.4.5" + zod "^3.23.8" + "@aws-crypto/crc32@3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@aws-crypto/crc32/-/crc32-3.0.0.tgz#07300eca214409c33e3ff769cd5697b57fdd38fa" From af3dcb27e59720bffcf0458b1ddb2066a8a0114c Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 8 Jan 2025 09:35:57 -0600 Subject: [PATCH 107/142] Format --- src/state/queries/unstable-profile-cache.ts | 2 +- src/types/atproto/post.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/state/queries/unstable-profile-cache.ts b/src/state/queries/unstable-profile-cache.ts index 40eae6dcda..7ffbfade4a 100644 --- a/src/state/queries/unstable-profile-cache.ts +++ b/src/state/queries/unstable-profile-cache.ts @@ -1,5 +1,5 @@ import {useCallback} from 'react' -import {QueryClient,useQueryClient} from '@tanstack/react-query' +import {QueryClient, useQueryClient} from '@tanstack/react-query' import * as atp from '#/types/atproto' diff --git a/src/types/atproto/post.ts b/src/types/atproto/post.ts index 993235237c..faca671a8f 100644 --- a/src/types/atproto/post.ts +++ b/src/types/atproto/post.ts @@ -60,9 +60,9 @@ export type View = media: View | undefined } -export function parseEmbedView( - { record }: AppBskyEmbedRecord.View, -): View | undefined { +export function parseEmbedView({ + record, +}: AppBskyEmbedRecord.View): View | undefined { if (AppBskyEmbedRecord.isViewRecord(record)) { return { type: 'post', From fad1685c10f8b03bfea0911684e69a6da0a984fd Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 8 Jan 2025 09:45:44 -0600 Subject: [PATCH 108/142] Format --- src/screens/Settings/components/PwiOptOut.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/screens/Settings/components/PwiOptOut.tsx b/src/screens/Settings/components/PwiOptOut.tsx index 4596f6cda6..23a466e3e9 100644 --- a/src/screens/Settings/components/PwiOptOut.tsx +++ b/src/screens/Settings/components/PwiOptOut.tsx @@ -1,6 +1,6 @@ import React from 'react' import {View} from 'react-native' -import {$Typed,ComAtprotoLabelDefs} from '@atproto/api' +import {$Typed, ComAtprotoLabelDefs} from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' From 7822bcd4161362e6ea2b8a2854a870c0f2b244c0 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 8 Jan 2025 10:06:48 -0600 Subject: [PATCH 109/142] Fix weird TS error --- src/state/cache/thread-mutes.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/state/cache/thread-mutes.tsx b/src/state/cache/thread-mutes.tsx index dc5104c140..37e948529b 100644 --- a/src/state/cache/thread-mutes.tsx +++ b/src/state/cache/thread-mutes.tsx @@ -69,7 +69,9 @@ function useMigrateMutes(setThreadMute: SetStateContext) { while (!cancelled) { const threads = persisted.get('mutedThreads') - const root = threads.findLast(uri => uri.includes(currentAccount.did)) + const root = threads + .reverse() + .find(uri => uri.includes(currentAccount.did)) if (!root) break From be7c6cb369fc62af689f780733e10c8bd184dc9e Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 8 Jan 2025 11:09:02 -0600 Subject: [PATCH 110/142] Remove patch --- patches/@atproto+api+0.14.0-next.1.patch | 39 ------------------------ 1 file changed, 39 deletions(-) delete mode 100644 patches/@atproto+api+0.14.0-next.1.patch diff --git a/patches/@atproto+api+0.14.0-next.1.patch b/patches/@atproto+api+0.14.0-next.1.patch deleted file mode 100644 index 675e1aa7ea..0000000000 --- a/patches/@atproto+api+0.14.0-next.1.patch +++ /dev/null @@ -1,39 +0,0 @@ -diff --git a/node_modules/@atproto/api/dist/moderation/types.d.ts b/node_modules/@atproto/api/dist/moderation/types.d.ts -index 4b1ebdd..33f6fb5 100644 ---- a/node_modules/@atproto/api/dist/moderation/types.d.ts -+++ b/node_modules/@atproto/api/dist/moderation/types.d.ts -@@ -1,4 +1,4 @@ --import { AppBskyActorDefs, AppBskyFeedDefs, AppBskyNotificationListNotifications, AppBskyGraphDefs, ComAtprotoLabelDefs } from '../client/index'; -+import { AppBskyActorDefs, AppBskyFeedDefs, AppBskyNotificationListNotifications, AppBskyGraphDefs, ComAtprotoLabelDefs, ChatBskyActorDefs } from '../client/index'; - import { KnownLabelValue } from './const/labels'; - export declare const CUSTOM_LABEL_VALUE_RE: RegExp; - export interface ModerationBehavior { -@@ -32,7 +32,7 @@ export interface InterpretedLabelValueDefinition extends ComAtprotoLabelDefs.Lab - }; - } - export type LabelDefinitionMap = Record; --export type ModerationSubjectProfile = AppBskyActorDefs.ProfileViewBasic | AppBskyActorDefs.ProfileView | AppBskyActorDefs.ProfileViewDetailed; -+export type ModerationSubjectProfile = AppBskyActorDefs.ProfileViewBasic | AppBskyActorDefs.ProfileView | AppBskyActorDefs.ProfileViewDetailed | ChatBskyActorDefs.ProfileViewBasic; - export type ModerationSubjectPost = AppBskyFeedDefs.PostView; - export type ModerationSubjectNotification = AppBskyNotificationListNotifications.Notification; - export type ModerationSubjectFeedGenerator = AppBskyFeedDefs.GeneratorView; -diff --git a/node_modules/@atproto/api/src/moderation/types.ts b/node_modules/@atproto/api/src/moderation/types.ts -index bbf8d84..16293e2 100644 ---- a/node_modules/@atproto/api/src/moderation/types.ts -+++ b/node_modules/@atproto/api/src/moderation/types.ts -@@ -4,6 +4,7 @@ import { - AppBskyNotificationListNotifications, - AppBskyGraphDefs, - ComAtprotoLabelDefs, -+ ChatBskyActorDefs, - } from '../client/index' - import { KnownLabelValue } from './const/labels' - -@@ -87,6 +88,7 @@ export type ModerationSubjectProfile = - | AppBskyActorDefs.ProfileViewBasic - | AppBskyActorDefs.ProfileView - | AppBskyActorDefs.ProfileViewDetailed -+ | ChatBskyActorDefs.ProfileViewBasic - - export type ModerationSubjectPost = AppBskyFeedDefs.PostView - From d05a11bb98b7c1b7573cdda62fb98e203110b02e Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 8 Jan 2025 13:29:47 -0600 Subject: [PATCH 111/142] Beter name --- src/types/atproto/post.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/types/atproto/post.ts b/src/types/atproto/post.ts index faca671a8f..085a2a96e0 100644 --- a/src/types/atproto/post.ts +++ b/src/types/atproto/post.ts @@ -60,7 +60,7 @@ export type View = media: View | undefined } -export function parseEmbedView({ +export function parseEmbedRecordView({ record, }: AppBskyEmbedRecord.View): View | undefined { if (AppBskyEmbedRecord.isViewRecord(record)) { @@ -125,11 +125,11 @@ export function parseEmbed( view: embed, } } else if (AppBskyEmbedRecord.isView(embed)) { - return parseEmbedView(embed) + return parseEmbedRecordView(embed) } else if (AppBskyEmbedRecordWithMedia.isView(embed)) { return { type: 'post_with_media', - view: parseEmbedView(embed.record), + view: parseEmbedRecordView(embed.record), media: parseEmbed(embed.media), } } From c488e92bcc20349bd5ee49f2fd7c3ceced2121a3 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 8 Jan 2025 15:29:22 -0600 Subject: [PATCH 112/142] It's memo, can validate --- src/view/com/post/Post.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx index cdd9fd41ea..bf256a4924 100644 --- a/src/view/com/post/Post.tsx +++ b/src/view/com/post/Post.tsx @@ -28,7 +28,6 @@ import {atoms as a} from '#/alf' import {ProfileHoverCard} from '#/components/ProfileHoverCard' import {RichText} from '#/components/RichText' import {SubtleWebHover} from '#/components/SubtleWebHover' -import * as atp from '#/types/atproto' import {ContentHider} from '../../../components/moderation/ContentHider' import {LabelsOnMyPost} from '../../../components/moderation/LabelsOnMe' import {PostAlerts} from '../../../components/moderation/PostAlerts' @@ -54,12 +53,7 @@ export function Post({ const moderationOpts = useModerationOpts() const record = useMemo( () => - atp.dangerousIsType( - post.record, - AppBskyFeedPost.isRecord, - ) - ? post.record - : undefined, + AppBskyFeedPost.isValidRecord(post.record) ? post.record : undefined, [post], ) const postShadowed = usePostShadow(post) From 27fe2606af7c97936599f6ef54878f9b97d33ecb Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 8 Jan 2025 19:20:21 -0600 Subject: [PATCH 113/142] Tighten up parseEmbed, dogfood --- src/types/atproto/post.ts | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/types/atproto/post.ts b/src/types/atproto/post.ts index 085a2a96e0..225726f41c 100644 --- a/src/types/atproto/post.ts +++ b/src/types/atproto/post.ts @@ -9,7 +9,7 @@ import { AppBskyLabelerDefs, } from '@atproto/api' -export type View = +export type Embed = | { type: 'post' view: AppBskyEmbedRecord.ViewRecord @@ -56,13 +56,17 @@ export type View = } | { type: 'post_with_media' - view: View | undefined - media: View | undefined + view: Embed + media: Embed + } + | { + type: 'unknown' + view: null } -export function parseEmbedRecordView({ - record, -}: AppBskyEmbedRecord.View): View | undefined { +export type EmbedType = Extract + +export function parseEmbedRecordView({record}: AppBskyEmbedRecord.View): Embed { if (AppBskyEmbedRecord.isViewRecord(record)) { return { type: 'post', @@ -103,12 +107,15 @@ export function parseEmbedRecordView({ type: 'starter_pack', view: record, } + } else { + return { + type: 'unknown', + view: null, + } } } -export function parseEmbed( - embed: AppBskyFeedDefs.PostView['embed'], -): View | undefined { +export function parseEmbed(embed: AppBskyFeedDefs.PostView['embed']): Embed { if (AppBskyEmbedImages.isView(embed)) { return { type: 'images', @@ -132,5 +139,10 @@ export function parseEmbed( view: parseEmbedRecordView(embed.record), media: parseEmbed(embed.media), } + } else { + return { + type: 'unknown', + view: null, + } } } From 3ed20f1050a3d13aef9e6d961d588e72327af8a2 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:02:58 -0600 Subject: [PATCH 114/142] Bump sdk --- package.json | 2 +- yarn.lock | 31 +++++++++++++++++++++---------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index e3d6b9ef0d..501beaefa0 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "icons:optimize": "svgo -f ./assets/icons" }, "dependencies": { - "@atproto/api": "0.14.0-next.2", + "@atproto/api": "0.14.0-next.6", "@bitdrift/react-native": "^0.6.2", "@braintree/sanitize-url": "^6.0.2", "@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet", diff --git a/yarn.lock b/yarn.lock index 52972b1d5a..c126332323 100644 --- a/yarn.lock +++ b/yarn.lock @@ -58,15 +58,15 @@ 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.14.0-next.2": - version "0.14.0-next.2" - resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.14.0-next.2.tgz#c42313217dc5cbbd81438706018963d4232a4ba6" - integrity sha512-1FADZQAklDozrGDxrb6ydkrlBBES4sKP7wJZTtwzqb1bSUOqRD8vjuvVvklt2ahhAQvslsBUC1wBrMa7VGS6hA== +"@atproto/api@0.14.0-next.6": + version "0.14.0-next.6" + resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.14.0-next.6.tgz#bdd3999cce9389c2068b591eb34ac8147adb7628" + integrity sha512-qVUn2iAIkZi8nrNX0nrWXLpqXlTGQ4mt0NX0wxKQ248B2ibi8Baneo/zJrtoTcb3cPTH3MJGNnfRNoYHVSOs+A== dependencies: "@atproto/common-web" "^0.3.2" - "@atproto/lexicon" "^0.4.5" + "@atproto/lexicon" "^0.4.6-next.5" "@atproto/syntax" "^0.3.1" - "@atproto/xrpc" "^0.6.6" + "@atproto/xrpc" "^0.6.7" await-lock "^2.2.2" multiformats "^9.9.0" tlds "^1.234.0" @@ -304,6 +304,17 @@ multiformats "^9.9.0" zod "^3.23.8" +"@atproto/lexicon@^0.4.6-next.5": + version "0.4.6-next.5" + resolved "https://registry.yarnpkg.com/@atproto/lexicon/-/lexicon-0.4.6-next.5.tgz#433a941cf8902afec15135f70cf2cbed37c35406" + integrity sha512-Id1atQ1rZ3dUGAUyBcauD+zs5lGHSmoAlC1Kwb2DEvkaWMv3oTXUjtdQxyb0/Kz4YaFI+nxLLRH9NBO+BipG+w== + dependencies: + "@atproto/common-web" "^0.3.2" + "@atproto/syntax" "^0.3.1" + iso-datestring-validator "^2.2.2" + multiformats "^9.9.0" + zod "^3.23.8" + "@atproto/oauth-provider@^0.2.10": version "0.2.10" resolved "https://registry.yarnpkg.com/@atproto/oauth-provider/-/oauth-provider-0.2.10.tgz#f9820d7f82c33d3b74e81a75873f50e1e654b901" @@ -473,10 +484,10 @@ "@atproto/lexicon" "^0.4.4" zod "^3.23.8" -"@atproto/xrpc@^0.6.6": - version "0.6.6" - resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.6.6.tgz#28f58270ef4a8056f7f718bd52512e74bcd3702f" - integrity sha512-umXEYVMo9/pyIBoKmIAIi64RXDW9tSXY+wqztlQ6I2GZtjLfNZqmAWU+wADk3SxUe54mvjxxGyA4TtyGtDMfhA== +"@atproto/xrpc@^0.6.7": + version "0.6.7" + resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.6.7.tgz#e72ac2009390ecf80cb075004d6160c92f38d33c" + integrity sha512-pbzZIONIskyGKxxG3s2wB7rQ2W1xu3ycfeYhKwk/E/ippeJFVxcof64iSC7f22+7JSKUJcxBeZ1piBB82vLj7g== dependencies: "@atproto/lexicon" "^0.4.5" zod "^3.23.8" From f6b21057b9a752a6a6527fbda5e9a0532d08d2ac Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:03:07 -0600 Subject: [PATCH 115/142] Use asPredicate --- src/lib/api/feed-manip.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/lib/api/feed-manip.ts b/src/lib/api/feed-manip.ts index e97ded6aa6..ed43f362ea 100644 --- a/src/lib/api/feed-manip.ts +++ b/src/lib/api/feed-manip.ts @@ -4,6 +4,7 @@ import { AppBskyEmbedRecordWithMedia, AppBskyFeedDefs, AppBskyFeedPost, + asPredicate, } from '@atproto/api' import {isPostInLanguage} from '../../locale/helpers' @@ -65,7 +66,10 @@ export class FeedViewPostsSlice { this.isFallbackMarker = true return } - if (!AppBskyFeedPost.isValidRecord(post.record)) { + if ( + !AppBskyFeedPost.isRecord(post.record) || + !asPredicate(AppBskyFeedPost.validateRecord)(post.record) + ) { return } const parent = reply?.parent @@ -95,7 +99,8 @@ export class FeedViewPostsSlice { } if ( !AppBskyFeedDefs.isPostView(parent) || - !AppBskyFeedPost.isValidRecord(parent.record) + !AppBskyFeedPost.isRecord(parent.record) || + !asPredicate(AppBskyFeedPost.validateRecord)(parent.record) ) { this.isOrphan = true return @@ -136,7 +141,8 @@ export class FeedViewPostsSlice { } if ( !AppBskyFeedDefs.isPostView(root) || - !AppBskyFeedPost.isValidRecord(root.record) + !AppBskyFeedPost.isRecord(root.record) || + !asPredicate(AppBskyFeedPost.validateRecord)(root.record) ) { this.isOrphan = true return From 155be6467a2792212ce02e14939bdd0b94a88cd3 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:03:25 -0600 Subject: [PATCH 116/142] Loosen types a bit --- src/state/queries/profile.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/state/queries/profile.ts b/src/state/queries/profile.ts index 5ac50fba55..0b49b24bbd 100644 --- a/src/state/queries/profile.ts +++ b/src/state/queries/profile.ts @@ -8,6 +8,7 @@ import { AtUri, BskyAgent, ComAtprotoRepoUploadBlob, + Un$Typed, } from '@atproto/api' import { QueryClient, @@ -117,8 +118,10 @@ export function usePrefetchProfileQuery() { interface ProfileUpdateParams { profile: AppBskyActorDefs.ProfileViewDetailed updates: - | AppBskyActorProfile.Record - | ((existing: AppBskyActorProfile.Record) => AppBskyActorProfile.Record) + | Un$Typed + | (( + existing: Un$Typed, + ) => Un$Typed) newUserAvatar?: RNImage | undefined | null newUserBanner?: RNImage | undefined | null checkCommitted?: (res: AppBskyActorGetProfile.Response) => boolean From fccc79feb2d7421f58c97686973586832a666940 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:03:41 -0600 Subject: [PATCH 117/142] use asPredicate --- src/view/com/post/Post.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx index bf256a4924..07e374692c 100644 --- a/src/view/com/post/Post.tsx +++ b/src/view/com/post/Post.tsx @@ -3,6 +3,7 @@ import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native' import { AppBskyFeedDefs, AppBskyFeedPost, + asPredicate, AtUri, ModerationDecision, RichText as RichTextAPI, @@ -53,7 +54,9 @@ export function Post({ const moderationOpts = useModerationOpts() const record = useMemo( () => - AppBskyFeedPost.isValidRecord(post.record) ? post.record : undefined, + asPredicate(AppBskyFeedPost.validateRecord)(post.record) + ? post.record + : undefined, [post], ) const postShadowed = usePostShadow(post) From eccbc566c74646d6945216d84bef7e97a78bf3ef Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:03:50 -0600 Subject: [PATCH 118/142] Fix types --- src/view/shell/desktop/LeftNav.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/shell/desktop/LeftNav.tsx b/src/view/shell/desktop/LeftNav.tsx index e9ba65ed02..98412cce0c 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 From df5c9be1d2a0778913a9a511aaa1fd3f22931c69 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:05:21 -0600 Subject: [PATCH 119/142] Use asPredicate --- src/state/queries/threadgate/util.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/state/queries/threadgate/util.ts b/src/state/queries/threadgate/util.ts index 75c1bdef1a..452fc84c79 100644 --- a/src/state/queries/threadgate/util.ts +++ b/src/state/queries/threadgate/util.ts @@ -1,4 +1,4 @@ -import {AppBskyFeedDefs, AppBskyFeedThreadgate} from '@atproto/api' +import {AppBskyFeedDefs, AppBskyFeedThreadgate, asPredicate} from '@atproto/api' import {ThreadgateAllowUISetting} from '#/state/queries/threadgate/types' @@ -7,7 +7,8 @@ export function threadgateViewToAllowUISetting( ): ThreadgateAllowUISetting[] { // Validate the record for clarity, since backwards compat code is a little confusing const threadgate = - threadgateView && AppBskyFeedThreadgate.isValidRecord(threadgateView.record) + threadgateView && + asPredicate(AppBskyFeedThreadgate.validateRecord)(threadgateView.record) ? threadgateView.record : undefined return threadgateRecordToAllowUISetting(threadgate) From 62ecada300ba0239980975e7ef5a3e0fe35c3fa8 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:06:00 -0600 Subject: [PATCH 120/142] Use asPredicate --- src/state/queries/threadgate/index.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/state/queries/threadgate/index.ts b/src/state/queries/threadgate/index.ts index 87e6d6666c..0eb1e72979 100644 --- a/src/state/queries/threadgate/index.ts +++ b/src/state/queries/threadgate/index.ts @@ -2,6 +2,7 @@ import { AppBskyFeedDefs, AppBskyFeedGetPostThread, AppBskyFeedThreadgate, + asPredicate, AtUri, BskyAgent, } from '@atproto/api' @@ -138,7 +139,10 @@ export async function getThreadgateRecord({ }), ) - if (data.value && AppBskyFeedThreadgate.isValidRecord(data.value)) { + if ( + data.value && + asPredicate(AppBskyFeedThreadgate.validateRecord)(data.value) + ) { return data.value } else { return null From 3a9f4c4e381c0cd679e3d1c59b0eaa3c449a2883 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:06:45 -0600 Subject: [PATCH 121/142] Use asPredicate --- src/state/queries/starter-packs.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/state/queries/starter-packs.ts b/src/state/queries/starter-packs.ts index 5b38b4de82..ec935836d3 100644 --- a/src/state/queries/starter-packs.ts +++ b/src/state/queries/starter-packs.ts @@ -4,6 +4,7 @@ import { AppBskyGraphGetStarterPack, AppBskyGraphStarterpack, AppBskyRichtextFacet, + asPredicate, AtUri, BskyAgent, RichText, @@ -368,7 +369,7 @@ export async function precacheStarterPack( starterPackView = starterPack } else if ( AppBskyGraphDefs.isStarterPackViewBasic(starterPack) && - AppBskyGraphStarterpack.isValidRecord(starterPack.record) + asPredicate(AppBskyGraphStarterpack.validateRecord)(starterPack.record) ) { const listView: AppBskyGraphDefs.ListViewBasic = { uri: starterPack.record.list, From 6854e6564bb51815e3ba2379141e1088d4f6f635 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:09:23 -0600 Subject: [PATCH 122/142] Clean up upsertProfile types --- src/state/queries/profile.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/state/queries/profile.ts b/src/state/queries/profile.ts index 0b49b24bbd..b50c17f93e 100644 --- a/src/state/queries/profile.ts +++ b/src/state/queries/profile.ts @@ -158,29 +158,29 @@ export function useProfileUpdateMutation() { ) } await agent.upsertProfile(async existing => { - existing = existing || {} + let next: Un$Typed = existing || {} if (typeof updates === 'function') { - existing = updates(existing) + next = updates(next) } else { - existing.displayName = updates.displayName - existing.description = updates.description + next.displayName = updates.displayName + next.description = updates.description if ('pinnedPost' in updates) { - existing.pinnedPost = updates.pinnedPost + next.pinnedPost = updates.pinnedPost } } if (newUserAvatarPromise) { const res = await newUserAvatarPromise - existing.avatar = res.data.blob + next.avatar = res.data.blob } else if (newUserAvatar === null) { - existing.avatar = undefined + next.avatar = undefined } if (newUserBannerPromise) { const res = await newUserBannerPromise - existing.banner = res.data.blob + next.banner = res.data.blob } else if (newUserBanner === null) { - existing.banner = undefined + next.banner = undefined } - return existing + return next }) await whenAppViewReady( agent, From 7126d8ca781794c766c11e784c919f643389ae85 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:11:18 -0600 Subject: [PATCH 123/142] Use asPredicate --- src/state/queries/postgate/index.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/state/queries/postgate/index.ts b/src/state/queries/postgate/index.ts index 84bc2d765d..6605ab8e68 100644 --- a/src/state/queries/postgate/index.ts +++ b/src/state/queries/postgate/index.ts @@ -4,6 +4,7 @@ import { AppBskyEmbedRecordWithMedia, AppBskyFeedDefs, AppBskyFeedPostgate, + asPredicate, AtUri, BskyAgent, } from '@atproto/api' @@ -60,7 +61,10 @@ export async function getPostgateRecord({ }), ) - if (data.value && AppBskyFeedPostgate.isValidRecord(data.value)) { + if ( + data.value && + asPredicate(AppBskyFeedPostgate.validateRecord)(data.value) + ) { return data.value } else { return undefined From 31472828ec9ae850258d7b47d153fa924149454f Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:16:35 -0600 Subject: [PATCH 124/142] Use Un util --- src/state/queries/list.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/state/queries/list.ts b/src/state/queries/list.ts index 7aec4bc669..3e9442fef5 100644 --- a/src/state/queries/list.ts +++ b/src/state/queries/list.ts @@ -8,6 +8,7 @@ import { BskyAgent, ComAtprotoRepoApplyWrites, Facet, + Un$Typed, } from '@atproto/api' import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query' import chunk from 'lodash.chunk' @@ -70,7 +71,7 @@ export function useListCreateMutation() { ) { throw new Error('Invalid list purpose: must be curatelist or modlist') } - const record: AppBskyGraphList.Record = { + const record: Un$Typed = { purpose, name, description, From 704d3c7497df478815ee1c60de569cb222cdb3e5 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:16:59 -0600 Subject: [PATCH 125/142] Fix types --- src/state/messages/convo/types.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/state/messages/convo/types.ts b/src/state/messages/convo/types.ts index fc50ed4b9d..69e15acc4e 100644 --- a/src/state/messages/convo/types.ts +++ b/src/state/messages/convo/types.ts @@ -147,8 +147,8 @@ export type ConvoStateUninitialized = { items: [] convo: ChatBskyConvoDefs.ConvoView | undefined error: undefined - sender: AppBskyActorDefs.ProfileViewBasic | undefined - recipients: AppBskyActorDefs.ProfileViewBasic[] | undefined + sender: ChatBskyActorDefs.ProfileViewBasic | undefined + recipients: ChatBskyActorDefs.ProfileViewBasic[] | undefined isFetchingHistory: false deleteMessage: undefined sendMessage: undefined @@ -159,8 +159,8 @@ export type ConvoStateInitializing = { items: [] convo: ChatBskyConvoDefs.ConvoView | undefined error: undefined - sender: AppBskyActorDefs.ProfileViewBasic | undefined - recipients: AppBskyActorDefs.ProfileViewBasic[] | undefined + sender: ChatBskyActorDefs.ProfileViewBasic | undefined + recipients: ChatBskyActorDefs.ProfileViewBasic[] | undefined isFetchingHistory: boolean deleteMessage: undefined sendMessage: undefined From 98e7d7401bae238b17bf23c3270ba2c0274f1f1b Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:17:35 -0600 Subject: [PATCH 126/142] Use new AnyProfileView --- src/state/cache/profile-shadow.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/state/cache/profile-shadow.ts b/src/state/cache/profile-shadow.ts index 2609f8bea7..1ce70045e8 100644 --- a/src/state/cache/profile-shadow.ts +++ b/src/state/cache/profile-shadow.ts @@ -69,7 +69,7 @@ export function useProfileShadow< * This is useful for when the profile is not guaranteed to be loaded yet. */ export function useMaybeProfileShadow< - TProfileView extends AppBskyActorDefs.ProfileView, + TProfileView extends atp.profile.AnyProfileView, >(profile?: TProfileView): Shadow | undefined { const [shadow, setShadow] = useState(() => profile ? shadows.get(profile) : undefined, From c60346b0fa653b1456c14897bb7f8d50e7c665fb Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:20:13 -0600 Subject: [PATCH 127/142] Use dangerousIsType --- src/screens/VideoFeed/index.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/screens/VideoFeed/index.tsx b/src/screens/VideoFeed/index.tsx index 88a83b45cf..e36132a162 100644 --- a/src/screens/VideoFeed/index.tsx +++ b/src/screens/VideoFeed/index.tsx @@ -90,6 +90,7 @@ import {ListFooter} from '#/components/Lists' import * as Hider from '#/components/moderation/Hider' import {RichText} from '#/components/RichText' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' import {Scrubber, VIDEO_PLAYER_BOTTOM_INSET} from './components/Scrubber' function createThreeVideoPlayers( @@ -694,7 +695,12 @@ function Overlay({ ) const rkey = new AtUri(post.uri).rkey - const record = AppBskyFeedPost.isRecord(post.record) ? post.record : undefined + const record = atp.dangerousIsType( + post.record, + AppBskyFeedPost.isRecord, + ) + ? post.record + : undefined const richText = new RichTextAPI({ text: record?.text || '', facets: record?.facets, From 06be7f887c19c5449d84e0d449e87d6298837d6c Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:21:17 -0600 Subject: [PATCH 128/142] Use asPredicate --- src/screens/StarterPack/Wizard/State.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/screens/StarterPack/Wizard/State.tsx b/src/screens/StarterPack/Wizard/State.tsx index 652e0afab3..b09d74a002 100644 --- a/src/screens/StarterPack/Wizard/State.tsx +++ b/src/screens/StarterPack/Wizard/State.tsx @@ -1,5 +1,9 @@ import React from 'react' -import {AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api' +import { + AppBskyGraphDefs, + AppBskyGraphStarterpack, + asPredicate, +} from '@atproto/api' import {GeneratorView} from '@atproto/api/dist/client/types/app/bsky/feed/defs' import {msg} from '@lingui/macro' @@ -124,7 +128,7 @@ export function Provider({ const createInitialState = (): State => { if ( starterPack && - AppBskyGraphStarterpack.isValidRecord(starterPack.record) + asPredicate(AppBskyGraphStarterpack.validateRecord)(starterPack.record) ) { return { canNext: true, From 707bb3a2c47837ea32c50a210de3f6a3ed0a4f8e Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:22:20 -0600 Subject: [PATCH 129/142] Use asPredicate --- src/screens/Settings/components/PwiOptOut.tsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/screens/Settings/components/PwiOptOut.tsx b/src/screens/Settings/components/PwiOptOut.tsx index 23a466e3e9..e0581da7fa 100644 --- a/src/screens/Settings/components/PwiOptOut.tsx +++ b/src/screens/Settings/components/PwiOptOut.tsx @@ -1,6 +1,6 @@ import React from 'react' import {View} from 'react-native' -import {$Typed, ComAtprotoLabelDefs} from '@atproto/api' +import {$Typed, asPredicate,ComAtprotoLabelDefs} from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -33,13 +33,14 @@ export function PwiOptOut() { profile, updates: existing => { // create labels attr if needed - const labels: $Typed = - ComAtprotoLabelDefs.isValidSelfLabels(existing.labels) - ? existing.labels - : { - $type: 'com.atproto.label.defs#selfLabels', - values: [], - } + const labels: $Typed = asPredicate( + ComAtprotoLabelDefs.validateSelfLabels, + )(existing.labels) + ? existing.labels + : { + $type: 'com.atproto.label.defs#selfLabels', + values: [], + } // toggle the label const hasLabel = labels.values.some( From e09858186ef771feebe6e8afbc496c8e75913ab3 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:24:43 -0600 Subject: [PATCH 130/142] Add fallback content-type to pass typecheck --- src/screens/Settings/components/ExportCarDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/screens/Settings/components/ExportCarDialog.tsx b/src/screens/Settings/components/ExportCarDialog.tsx index 2de3895d31..685707259d 100644 --- a/src/screens/Settings/components/ExportCarDialog.tsx +++ b/src/screens/Settings/components/ExportCarDialog.tsx @@ -36,7 +36,7 @@ export function ExportCarDialog({ const saveRes = await saveBytesToDisk( 'repo.car', downloadRes.data, - downloadRes.headers['content-type'], + downloadRes.headers['content-type'] || 'application/vnd.ipld.car', ) if (saveRes) { From 58f1e87457c7571d5cb79016f38069d333e99ed9 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:26:48 -0600 Subject: [PATCH 131/142] Clean up upsertProfile types --- src/screens/Onboarding/StepFinished.tsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/screens/Onboarding/StepFinished.tsx b/src/screens/Onboarding/StepFinished.tsx index bf6d984f77..1e1c6aacd8 100644 --- a/src/screens/Onboarding/StepFinished.tsx +++ b/src/screens/Onboarding/StepFinished.tsx @@ -1,6 +1,11 @@ import React from 'react' import {View} from 'react-native' -import {AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api' +import { + AppBskyActorProfile, + AppBskyGraphDefs, + AppBskyGraphStarterpack, + Un$Typed, +} from '@atproto/api' import {SavedFeed} from '@atproto/api/dist/client/types/app/bsky/actor/defs' import {TID} from '@atproto/common-web' import {msg, Trans} from '@lingui/macro' @@ -142,29 +147,29 @@ export function StepFinished() { : undefined await agent.upsertProfile(async existing => { - existing = existing ?? {} + let next: Un$Typed = existing ?? {} if (blobPromise) { const res = await blobPromise if (res.data.blob) { - existing.avatar = res.data.blob + next.avatar = res.data.blob } } if (starterPack) { - existing.joinedViaStarterPack = { + next.joinedViaStarterPack = { uri: starterPack.uri, cid: starterPack.cid, } } - existing.displayName = '' + next.displayName = '' // HACKFIX // creating a bunch of identical profile objects is breaking the relay // tossing this unspecced field onto it to reduce the size of the problem // -prf - existing.createdAt = new Date().toISOString() - return existing + next.createdAt = new Date().toISOString() + return next }) logEvent('onboarding:finished:avatarResult', { From 2269acde59f8835d42cd6ba327c54b5e241a09cc Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:30:36 -0600 Subject: [PATCH 132/142] Align types --- src/components/dms/MessagesListHeader.tsx | 4 ++-- src/screens/Messages/Conversation.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/dms/MessagesListHeader.tsx b/src/components/dms/MessagesListHeader.tsx index f8d9b290d8..ce051c79f1 100644 --- a/src/components/dms/MessagesListHeader.tsx +++ b/src/components/dms/MessagesListHeader.tsx @@ -31,7 +31,7 @@ export let MessagesListHeader = ({ profile, moderation, }: { - profile?: Shadow + profile?: Shadow moderation?: ModerationDecision }): React.ReactNode => { const t = useTheme() @@ -138,7 +138,7 @@ function HeaderReady({ moderation, blockInfo, }: { - profile: Shadow + profile: Shadow moderation: ModerationDecision blockInfo: { listBlocks: ModerationCause[] diff --git a/src/screens/Messages/Conversation.tsx b/src/screens/Messages/Conversation.tsx index f51822952f..69af0ea58f 100644 --- a/src/screens/Messages/Conversation.tsx +++ b/src/screens/Messages/Conversation.tsx @@ -165,7 +165,7 @@ function InnerReady({ setHasScrolled, }: { moderation: ModerationDecision - recipient: Shadow + recipient: Shadow hasScrolled: boolean setHasScrolled: React.Dispatch> }) { From 8f57d6eddeaa1071bca327ea7b412673b8c54351 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:31:41 -0600 Subject: [PATCH 133/142] Use dangerousIsType --- src/screens/Messages/components/MessageInputEmbed.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/screens/Messages/components/MessageInputEmbed.tsx b/src/screens/Messages/components/MessageInputEmbed.tsx index 827c62f061..af6906dd91 100644 --- a/src/screens/Messages/components/MessageInputEmbed.tsx +++ b/src/screens/Messages/components/MessageInputEmbed.tsx @@ -30,6 +30,7 @@ import {ContentHider} from '#/components/moderation/ContentHider' import {PostAlerts} from '#/components/moderation/PostAlerts' import {RichText} from '#/components/RichText' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' export function useMessageEmbed() { const route = @@ -111,7 +112,13 @@ export function MessageInputEmbed({ ) const {rt, record} = useMemo(() => { - if (post && AppBskyFeedPost.isValidRecord(post.record)) { + if ( + post && + atp.dangerousIsType( + post.record, + AppBskyFeedPost.isRecord, + ) + ) { return { rt: new RichTextAPI({ text: post.record.text, From 4d8c580a90185c0065f739d34e1a32eb95bef49d Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:32:34 -0600 Subject: [PATCH 134/142] Use dangerousIsType --- src/components/VideoPostCard.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/VideoPostCard.tsx b/src/components/VideoPostCard.tsx index 008274969e..3ddd61e978 100644 --- a/src/components/VideoPostCard.tsx +++ b/src/components/VideoPostCard.tsx @@ -27,6 +27,7 @@ import {Link} from '#/components/Link' import {MediaInsetBorder} from '#/components/MediaInsetBorder' import * as Hider from '#/components/moderation/Hider' import {Text} from '#/components/Typography' +import * as atp from '#/types/atproto' function getBlackColor(t: ReturnType) { return select(t.name, { @@ -78,7 +79,12 @@ export function VideoPostCard({ if (!AppBskyEmbedVideo.isView(embed)) return null const author = post.author - const text = AppBskyFeedPost.isRecord(post.record) ? post.record?.text : '' + const text = atp.dangerousIsType( + post.record, + AppBskyFeedPost.isRecord, + ) + ? post.record?.text + : '' const likeCount = post?.likeCount ?? 0 const repostCount = post?.repostCount ?? 0 const {thumbnail} = embed From f8a52aa527a13a74941841b0de8bb82a27cc9895 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:33:21 -0600 Subject: [PATCH 135/142] Use asPredicate --- src/components/StarterPack/QrCodeDialog.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/components/StarterPack/QrCodeDialog.tsx b/src/components/StarterPack/QrCodeDialog.tsx index 79de3bfba5..63d58a0f44 100644 --- a/src/components/StarterPack/QrCodeDialog.tsx +++ b/src/components/StarterPack/QrCodeDialog.tsx @@ -4,7 +4,11 @@ import type ViewShot from 'react-native-view-shot' import {requestMediaLibraryPermissionsAsync} from 'expo-image-picker' import {createAssetAsync} from 'expo-media-library' import * as Sharing from 'expo-sharing' -import {AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api' +import { + AppBskyGraphDefs, + AppBskyGraphStarterpack, + asPredicate, +} from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -77,7 +81,11 @@ export function QrCodeDialog({ } else { setIsProcessing(true) - if (!AppBskyGraphStarterpack.isValidRecord(starterPack.record)) { + if ( + !asPredicate(AppBskyGraphStarterpack.validateRecord)( + starterPack.record, + ) + ) { return } From c68688a85069c81ef8a269dcbe38f9be0caca024 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:33:56 -0600 Subject: [PATCH 136/142] Align types --- src/components/dms/ReportDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dms/ReportDialog.tsx b/src/components/dms/ReportDialog.tsx index ddb970354a..71cca897a5 100644 --- a/src/components/dms/ReportDialog.tsx +++ b/src/components/dms/ReportDialog.tsx @@ -287,7 +287,7 @@ function DoneStep({ }: { convoId: string currentScreen: 'list' | 'conversation' - profile: AppBskyActorDefs.ProfileViewBasic + profile: AppBskyActorDefs.ProfileViewDetailed }) { const {_} = useLingui() const navigation = useNavigation() From 38a0d299d8e1f088d2aed4c610a8ab8b07fd27b6 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:51:54 -0600 Subject: [PATCH 137/142] Convert findLast --- src/components/dms/MessagesListHeader.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/dms/MessagesListHeader.tsx b/src/components/dms/MessagesListHeader.tsx index ce051c79f1..29f6672bc3 100644 --- a/src/components/dms/MessagesListHeader.tsx +++ b/src/components/dms/MessagesListHeader.tsx @@ -157,9 +157,12 @@ function HeaderReady({ moderation.ui('displayName'), ) - const latestMessageFromOther = convoState.items.findLast( - item => item.type === 'message' && item.message.sender.did === profile.did, - ) + const latestMessageFromOther = convoState.items + .reverse() + .find( + item => + item.type === 'message' && item.message.sender.did === profile.did, + ) const latestReportableMessage = latestMessageFromOther?.type === 'message' From fbc30cc3262fa40fda077fe6bddd9289b12b59cf Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 5 Feb 2025 11:54:21 -0600 Subject: [PATCH 138/142] Align types --- src/components/dms/ConvoMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dms/ConvoMenu.tsx b/src/components/dms/ConvoMenu.tsx index 2b365f16dc..003d849379 100644 --- a/src/components/dms/ConvoMenu.tsx +++ b/src/components/dms/ConvoMenu.tsx @@ -145,7 +145,7 @@ function MenuContent({ blockedByListControl, }: { convo: ChatBskyConvoDefs.ConvoView - profile: Shadow + profile: Shadow showMarkAsRead?: boolean blockInfo: { listBlocks: ModerationCause[] From 2ad2219be6270d8a471a5e20a5a514afdf503e32 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 6 Feb 2025 09:56:24 -0600 Subject: [PATCH 139/142] Just ignore type errors and use findLast --- src/components/dms/MessagesListHeader.tsx | 10 ++++------ src/state/cache/thread-mutes.tsx | 5 ++--- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/components/dms/MessagesListHeader.tsx b/src/components/dms/MessagesListHeader.tsx index 29f6672bc3..39e8f69055 100644 --- a/src/components/dms/MessagesListHeader.tsx +++ b/src/components/dms/MessagesListHeader.tsx @@ -157,12 +157,10 @@ function HeaderReady({ moderation.ui('displayName'), ) - const latestMessageFromOther = convoState.items - .reverse() - .find( - item => - item.type === 'message' && item.message.sender.did === profile.did, - ) + // @ts-ignore findLast is polyfilled - esb + const latestMessageFromOther = convoState.items.findLast( + item => item.type === 'message' && item.message.sender.did === profile.did, + ) const latestReportableMessage = latestMessageFromOther?.type === 'message' diff --git a/src/state/cache/thread-mutes.tsx b/src/state/cache/thread-mutes.tsx index 37e948529b..4492977f22 100644 --- a/src/state/cache/thread-mutes.tsx +++ b/src/state/cache/thread-mutes.tsx @@ -69,9 +69,8 @@ function useMigrateMutes(setThreadMute: SetStateContext) { while (!cancelled) { const threads = persisted.get('mutedThreads') - const root = threads - .reverse() - .find(uri => uri.includes(currentAccount.did)) + // @ts-ignore findLast is polyfilled - esb + const root = threads.findLast(uri => uri.includes(currentAccount.did)) if (!root) break From 59e32b3005b46dd491c2363861c327a24607460a Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 6 Feb 2025 10:11:48 -0600 Subject: [PATCH 140/142] Rename atproto -> bsky --- src/components/FeedCard.tsx | 4 ++-- src/components/FeedInterstitials.tsx | 4 ++-- src/components/ListCard.tsx | 4 ++-- src/components/MediaPreview.tsx | 2 +- src/components/ProfileCard.tsx | 16 ++++++++-------- src/components/StarterPack/QrCode.tsx | 4 ++-- src/components/StarterPack/StarterPackCard.tsx | 14 +++++++------- .../StarterPack/Wizard/WizardListCard.tsx | 4 ++-- src/components/VideoPostCard.tsx | 4 ++-- src/components/WhoCanReply.tsx | 4 ++-- src/components/dms/ConvoMenu.tsx | 6 +++--- src/components/dms/MessagesListBlockedFooter.tsx | 4 ++-- .../dms/dialogs/SearchablePeopleList.tsx | 6 +++--- src/components/dms/util.ts | 4 ++-- src/components/hooks/useFollowMethods.ts | 4 ++-- src/lib/generate-starterpack.ts | 4 ++-- src/lib/moderation/blocked-and-muted.ts | 2 +- src/lib/strings/starter-pack.ts | 2 +- src/screens/Messages/components/ChatListItem.tsx | 4 ++-- .../Messages/components/MessageInputEmbed.tsx | 4 ++-- src/screens/Onboarding/StepFinished.tsx | 4 ++-- src/screens/Signup/index.tsx | 4 ++-- .../StarterPack/StarterPackLandingScreen.tsx | 4 ++-- src/screens/StarterPack/StarterPackScreen.tsx | 4 ++-- src/screens/StarterPack/Wizard/State.tsx | 6 +++--- src/screens/StarterPack/Wizard/StepProfiles.tsx | 4 ++-- src/screens/StarterPack/Wizard/index.tsx | 4 ++-- src/screens/VideoFeed/index.tsx | 4 ++-- src/state/cache/profile-shadow.ts | 12 ++++++------ src/state/queries/notifications/util.ts | 6 +++--- src/state/queries/post-thread.ts | 4 ++-- src/state/queries/profile.ts | 10 +++++----- src/state/queries/starter-packs.ts | 4 ++-- src/state/queries/unstable-profile-cache.ts | 6 +++--- src/state/queries/util.ts | 6 +++--- src/types/{atproto => bsky}/index.ts | 4 ++-- src/types/{atproto => bsky}/post.ts | 0 src/types/{atproto => bsky}/profile.ts | 0 src/types/{atproto => bsky}/starterPack.ts | 0 src/view/com/lists/ListMembers.tsx | 6 +++--- .../com/notifications/NotificationFeedItem.tsx | 6 +++--- src/view/com/post-thread/PostThreadItem.tsx | 4 ++-- src/view/com/posts/PostFeedItem.tsx | 2 +- src/view/com/profile/FollowButton.tsx | 4 ++-- src/view/com/profile/ProfileCard.tsx | 2 +- src/view/com/util/UserAvatar.tsx | 4 ++-- src/view/com/util/post-embeds/QuoteEmbed.tsx | 4 ++-- 47 files changed, 109 insertions(+), 109 deletions(-) rename src/types/{atproto => bsky}/index.ts (87%) rename src/types/{atproto => bsky}/post.ts (100%) rename src/types/{atproto => bsky}/profile.ts (100%) rename src/types/{atproto => bsky}/starterPack.ts (100%) diff --git a/src/components/FeedCard.tsx b/src/components/FeedCard.tsx index cd8dba4aca..709d0631dc 100644 --- a/src/components/FeedCard.tsx +++ b/src/components/FeedCard.tsx @@ -31,7 +31,7 @@ import {Loader} from '#/components/Loader' import * as Prompt from '#/components/Prompt' import {RichText, RichTextProps} from '#/components/RichText' import {Text} from '#/components/Typography' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' type Props = { view: AppBskyFeedDefs.GeneratorView @@ -115,7 +115,7 @@ export function TitleAndByline({ creator, }: { title: string - creator?: atp.profile.AnyProfileView + creator?: bsky.profile.AnyProfileView }) { const t = useTheme() diff --git a/src/components/FeedInterstitials.tsx b/src/components/FeedInterstitials.tsx index 3bc909b06c..eafed25e50 100644 --- a/src/components/FeedInterstitials.tsx +++ b/src/components/FeedInterstitials.tsx @@ -27,7 +27,7 @@ import {PersonPlus_Stroke2_Corner0_Rounded as Person} from '#/components/icons/P import {InlineLinkText} from '#/components/Link' import * as ProfileCard from '#/components/ProfileCard' import {Text} from '#/components/Typography' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' import {ProgressGuideList} from './ProgressGuide/List' const MOBILE_CARD_WIDTH = 300 @@ -229,7 +229,7 @@ export function ProfileGrid({ viewContext = 'feed', }: { isSuggestionsLoading: boolean - profiles: atp.profile.AnyProfileView[] + profiles: bsky.profile.AnyProfileView[] recId?: number error: Error | null viewContext: 'profile' | 'feed' diff --git a/src/components/ListCard.tsx b/src/components/ListCard.tsx index 13fc4e222b..30156ee0d3 100644 --- a/src/components/ListCard.tsx +++ b/src/components/ListCard.tsx @@ -25,7 +25,7 @@ import { import {Link as InternalLink, LinkProps} from '#/components/Link' import * as Hider from '#/components/moderation/Hider' import {Text} from '#/components/Typography' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' /* * This component is based on `FeedCard` and is tightly coupled with that @@ -107,7 +107,7 @@ export function TitleAndByline({ modUi, }: { title: string - creator?: atp.profile.AnyProfileView + creator?: bsky.profile.AnyProfileView purpose?: AppBskyGraphDefs.ListView['purpose'] modUi?: ModerationUI }) { diff --git a/src/components/MediaPreview.tsx b/src/components/MediaPreview.tsx index 96fb0b2812..9e5e095244 100644 --- a/src/components/MediaPreview.tsx +++ b/src/components/MediaPreview.tsx @@ -9,7 +9,7 @@ import {atoms as a, useTheme} from '#/alf' import {MediaInsetBorder} from '#/components/MediaInsetBorder' import {Text} from '#/components/Typography' import {PlayButtonIcon} from '#/components/video/PlayButtonIcon' -import {parseEmbed} from '#/types/atproto/post' +import {parseEmbed} from '#/types/bsky/post' /** * Streamlined MediaPreview component which just handles images, gifs, and videos diff --git a/src/components/ProfileCard.tsx b/src/components/ProfileCard.tsx index a9ae464aca..b56112dcf2 100644 --- a/src/components/ProfileCard.tsx +++ b/src/components/ProfileCard.tsx @@ -24,14 +24,14 @@ import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus import {Link as InternalLink, LinkProps} from '#/components/Link' import {RichText} from '#/components/RichText' import {Text} from '#/components/Typography' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' export function Default({ profile, moderationOpts, logContext = 'ProfileCard', }: { - profile: atp.profile.AnyProfileView + profile: bsky.profile.AnyProfileView moderationOpts: ModerationOpts logContext?: 'ProfileCard' | 'StarterPackProfilesList' }) { @@ -51,7 +51,7 @@ export function Card({ moderationOpts, logContext = 'ProfileCard', }: { - profile: atp.profile.AnyProfileView + profile: bsky.profile.AnyProfileView moderationOpts: ModerationOpts logContext?: 'ProfileCard' | 'StarterPackProfilesList' }) { @@ -101,7 +101,7 @@ export function Link({ style, ...rest }: { - profile: atp.profile.AnyProfileView + profile: bsky.profile.AnyProfileView } & Omit) { const {_} = useLingui() return ( @@ -126,7 +126,7 @@ export function Avatar({ profile, moderationOpts, }: { - profile: atp.profile.AnyProfileView + profile: bsky.profile.AnyProfileView moderationOpts: ModerationOpts }) { const moderation = moderateProfile(profile, moderationOpts) @@ -161,7 +161,7 @@ export function NameAndHandle({ profile, moderationOpts, }: { - profile: atp.profile.AnyProfileView + profile: bsky.profile.AnyProfileView moderationOpts: ModerationOpts }) { const t = useTheme() @@ -224,7 +224,7 @@ export function Description({ profile: profileUnshadowed, numberOfLines = 3, }: { - profile: atp.profile.AnyProfileView + profile: bsky.profile.AnyProfileView numberOfLines?: number }) { const profile = useProfileShadow(profileUnshadowed) @@ -280,7 +280,7 @@ export function DescriptionPlaceholder({ } export type FollowButtonProps = { - profile: atp.profile.AnyProfileView + profile: bsky.profile.AnyProfileView moderationOpts: ModerationOpts logContext: LogEvents['profile:follow']['logContext'] & LogEvents['profile:unfollow']['logContext'] diff --git a/src/components/StarterPack/QrCode.tsx b/src/components/StarterPack/QrCode.tsx index a6e3208fff..6443ec694c 100644 --- a/src/components/StarterPack/QrCode.tsx +++ b/src/components/StarterPack/QrCode.tsx @@ -13,7 +13,7 @@ import {useTheme} from '#/alf' import {atoms as a} from '#/alf' import {LinearGradientBackground} from '#/components/LinearGradientBackground' import {Text} from '#/components/Typography' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' const LazyViewShot = React.lazy( // @ts-expect-error dynamic import @@ -32,7 +32,7 @@ export const QrCode = React.forwardRef(function QrCode( const {record} = starterPack if ( - !atp.dangerousIsType( + !bsky.dangerousIsType( record, AppBskyGraphStarterpack.isRecord, ) diff --git a/src/components/StarterPack/StarterPackCard.tsx b/src/components/StarterPack/StarterPackCard.tsx index 72deca9f6b..ab9c01fc06 100644 --- a/src/components/StarterPack/StarterPackCard.tsx +++ b/src/components/StarterPack/StarterPackCard.tsx @@ -15,12 +15,12 @@ import {atoms as a, useTheme} from '#/alf' import {StarterPack} from '#/components/icons/StarterPack' import {Link as BaseLink, LinkProps as BaseLinkProps} from '#/components/Link' import {Text} from '#/components/Typography' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' export function Default({ starterPack, }: { - starterPack?: atp.starterPack.AnyStarterPackView + starterPack?: bsky.starterPack.AnyStarterPackView }) { if (!starterPack) return null return ( @@ -33,7 +33,7 @@ export function Default({ export function Notification({ starterPack, }: { - starterPack?: atp.starterPack.AnyStarterPackView + starterPack?: bsky.starterPack.AnyStarterPackView }) { if (!starterPack) return null return ( @@ -48,7 +48,7 @@ export function Card({ noIcon, noDescription, }: { - starterPack: atp.starterPack.AnyStarterPackView + starterPack: bsky.starterPack.AnyStarterPackView noIcon?: boolean noDescription?: boolean }) { @@ -59,7 +59,7 @@ export function Card({ const {currentAccount} = useSession() if ( - !atp.dangerousIsType( + !bsky.dangerousIsType( record, AppBskyGraphStarterpack.isRecord, ) @@ -106,7 +106,7 @@ export function Link({ starterPack, children, }: { - starterPack: atp.starterPack.AnyStarterPackView + starterPack: bsky.starterPack.AnyStarterPackView onPress?: () => void children: BaseLinkProps['children'] }) { @@ -145,7 +145,7 @@ export function Link({ export function Embed({ starterPack, }: { - starterPack: atp.starterPack.AnyStarterPackView + starterPack: bsky.starterPack.AnyStarterPackView }) { const t = useTheme() const imageUri = getStarterPackOgCard(starterPack) diff --git a/src/components/StarterPack/Wizard/WizardListCard.tsx b/src/components/StarterPack/Wizard/WizardListCard.tsx index 77eb8365ae..e1a70a0b71 100644 --- a/src/components/StarterPack/Wizard/WizardListCard.tsx +++ b/src/components/StarterPack/Wizard/WizardListCard.tsx @@ -22,7 +22,7 @@ import {Button, ButtonText} from '#/components/Button' import * as Toggle from '#/components/forms/Toggle' import {Checkbox} from '#/components/forms/Toggle' import {Text} from '#/components/Typography' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' function WizardListCard({ type, @@ -124,7 +124,7 @@ export function WizardProfileCard({ btnType: 'checkbox' | 'remove' state: WizardState dispatch: (action: WizardAction) => void - profile: atp.profile.AnyProfileView + profile: bsky.profile.AnyProfileView moderationOpts: ModerationOpts }) { const {currentAccount} = useSession() diff --git a/src/components/VideoPostCard.tsx b/src/components/VideoPostCard.tsx index 3ddd61e978..3e396e7d3d 100644 --- a/src/components/VideoPostCard.tsx +++ b/src/components/VideoPostCard.tsx @@ -27,7 +27,7 @@ import {Link} from '#/components/Link' import {MediaInsetBorder} from '#/components/MediaInsetBorder' import * as Hider from '#/components/moderation/Hider' import {Text} from '#/components/Typography' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' function getBlackColor(t: ReturnType) { return select(t.name, { @@ -79,7 +79,7 @@ export function VideoPostCard({ if (!AppBskyEmbedVideo.isView(embed)) return null const author = post.author - const text = atp.dangerousIsType( + const text = bsky.dangerousIsType( post.record, AppBskyFeedPost.isRecord, ) diff --git a/src/components/WhoCanReply.tsx b/src/components/WhoCanReply.tsx index a992aeccce..f5280beb6e 100644 --- a/src/components/WhoCanReply.tsx +++ b/src/components/WhoCanReply.tsx @@ -29,7 +29,7 @@ import {Earth_Stroke2_Corner0_Rounded as Earth} from '#/components/icons/Globe' import {Group3_Stroke2_Corner0_Rounded as Group} from '#/components/icons/Group' import {InlineLinkText} from '#/components/Link' import {Text} from '#/components/Typography' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' import {PencilLine_Stroke2_Corner0_Rounded as PencilLine} from './icons/Pencil' interface WhoCanReplyProps { @@ -49,7 +49,7 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) { * unexpectedly, we should check to make sure it's for sure the root URI. */ const rootUri = - atp.dangerousIsType( + bsky.dangerousIsType( post.record, AppBskyFeedPost.isRecord, ) && post.record.reply?.root diff --git a/src/components/dms/ConvoMenu.tsx b/src/components/dms/ConvoMenu.tsx index 003d849379..590f25dd31 100644 --- a/src/components/dms/ConvoMenu.tsx +++ b/src/components/dms/ConvoMenu.tsx @@ -30,7 +30,7 @@ import { import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute} from '#/components/icons/Speaker' import * as Menu from '#/components/Menu' import * as Prompt from '#/components/Prompt' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' import {Bubble_Stroke2_Corner2_Rounded as Bubble} from '../icons/Bubble' import {ReportDialog} from './ReportDialog' @@ -46,7 +46,7 @@ let ConvoMenu = ({ style, }: { convo: ChatBskyConvoDefs.ConvoView - profile: Shadow + profile: Shadow control?: Menu.MenuControlProps currentScreen: 'list' | 'conversation' showMarkAsRead?: boolean @@ -145,7 +145,7 @@ function MenuContent({ blockedByListControl, }: { convo: ChatBskyConvoDefs.ConvoView - profile: Shadow + profile: Shadow showMarkAsRead?: boolean blockInfo: { listBlocks: ModerationCause[] diff --git a/src/components/dms/MessagesListBlockedFooter.tsx b/src/components/dms/MessagesListBlockedFooter.tsx index 6c3592cb1a..9c63ef2c7e 100644 --- a/src/components/dms/MessagesListBlockedFooter.tsx +++ b/src/components/dms/MessagesListBlockedFooter.tsx @@ -14,7 +14,7 @@ import {BlockedByListDialog} from '#/components/dms/BlockedByListDialog' import {LeaveConvoPrompt} from '#/components/dms/LeaveConvoPrompt' import {ReportConversationPrompt} from '#/components/dms/ReportConversationPrompt' import {Text} from '#/components/Typography' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' export function MessagesListBlockedFooter({ recipient: initialRecipient, @@ -22,7 +22,7 @@ export function MessagesListBlockedFooter({ hasMessages, moderation, }: { - recipient: atp.profile.AnyProfileView + recipient: bsky.profile.AnyProfileView convoId: string hasMessages: boolean moderation: ModerationDecision diff --git a/src/components/dms/dialogs/SearchablePeopleList.tsx b/src/components/dms/dialogs/SearchablePeopleList.tsx index 52ed297766..29356b5873 100644 --- a/src/components/dms/dialogs/SearchablePeopleList.tsx +++ b/src/components/dms/dialogs/SearchablePeopleList.tsx @@ -28,14 +28,14 @@ import {useInteractionState} from '#/components/hooks/useInteractionState' import {MagnifyingGlass2_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass2' import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times' import {Text} from '#/components/Typography' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' type Item = | { type: 'profile' key: string enabled: boolean - profile: atp.profile.AnyProfileView + profile: bsky.profile.AnyProfileView } | { type: 'empty' @@ -331,7 +331,7 @@ function ProfileCard({ onPress, }: { enabled: boolean - profile: atp.profile.AnyProfileView + profile: bsky.profile.AnyProfileView moderationOpts: ModerationOpts onPress: (did: string) => void }) { diff --git a/src/components/dms/util.ts b/src/components/dms/util.ts index 92e2337a9e..7315f5fc9c 100644 --- a/src/components/dms/util.ts +++ b/src/components/dms/util.ts @@ -1,6 +1,6 @@ -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' -export function canBeMessaged(profile: atp.profile.AnyProfileView) { +export function canBeMessaged(profile: bsky.profile.AnyProfileView) { switch (profile.associated?.chat?.allowIncoming) { case 'none': return false diff --git a/src/components/hooks/useFollowMethods.ts b/src/components/hooks/useFollowMethods.ts index ffce60ea2c..e6b3f2c473 100644 --- a/src/components/hooks/useFollowMethods.ts +++ b/src/components/hooks/useFollowMethods.ts @@ -8,13 +8,13 @@ import {Shadow} from '#/state/cache/types' import {useProfileFollowMutationQueue} from '#/state/queries/profile' import {useRequireAuth} from '#/state/session' import * as Toast from '#/view/com/util/Toast' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' export function useFollowMethods({ profile, logContext, }: { - profile: Shadow + profile: Shadow logContext: LogEvents['profile:follow']['logContext'] & LogEvents['profile:unfollow']['logContext'] }) { diff --git a/src/lib/generate-starterpack.ts b/src/lib/generate-starterpack.ts index 5137983c43..11e3343293 100644 --- a/src/lib/generate-starterpack.ts +++ b/src/lib/generate-starterpack.ts @@ -15,7 +15,7 @@ import {sanitizeDisplayName} from '#/lib/strings/display-names' import {sanitizeHandle} from '#/lib/strings/handles' import {enforceLen} from '#/lib/strings/helpers' import {useAgent} from '#/state/session' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' export const createStarterPackList = async ({ name, @@ -27,7 +27,7 @@ export const createStarterPackList = async ({ name: string description?: string descriptionFacets?: Facet[] - profiles: atp.profile.AnyProfileView[] + profiles: bsky.profile.AnyProfileView[] agent: BskyAgent }): Promise<{uri: string; cid: string}> => { if (profiles.length === 0) throw new Error('No profiles given') diff --git a/src/lib/moderation/blocked-and-muted.ts b/src/lib/moderation/blocked-and-muted.ts index bee03fa6d3..8eaab80694 100644 --- a/src/lib/moderation/blocked-and-muted.ts +++ b/src/lib/moderation/blocked-and-muted.ts @@ -1,4 +1,4 @@ -import * as atp from '#/types/atproto' +import * as atp from '#/types/bsky' export function isBlockedOrBlocking(profile: atp.profile.AnyProfileView) { return profile.viewer?.blockedBy || profile.viewer?.blocking diff --git a/src/lib/strings/starter-pack.ts b/src/lib/strings/starter-pack.ts index 2e4497a443..609a233c0c 100644 --- a/src/lib/strings/starter-pack.ts +++ b/src/lib/strings/starter-pack.ts @@ -1,6 +1,6 @@ import {AtUri} from '@atproto/api' -import * as atp from '#/types/atproto' +import * as atp from '#/types/bsky' export function createStarterPackLinkFromAndroidReferrer( referrerQueryString: string, diff --git a/src/screens/Messages/components/ChatListItem.tsx b/src/screens/Messages/components/ChatListItem.tsx index b4aa9ab979..eed3236ace 100644 --- a/src/screens/Messages/components/ChatListItem.tsx +++ b/src/screens/Messages/components/ChatListItem.tsx @@ -43,7 +43,7 @@ import {Link} from '#/components/Link' import {useMenuControl} from '#/components/Menu' import {PostAlerts} from '#/components/moderation/PostAlerts' import {Text} from '#/components/Typography' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' export let ChatListItem = ({ convo, @@ -78,7 +78,7 @@ function ChatListItemReady({ moderationOpts, }: { convo: ChatBskyConvoDefs.ConvoView - profile: atp.profile.AnyProfileView + profile: bsky.profile.AnyProfileView moderationOpts: ModerationOpts }) { const t = useTheme() diff --git a/src/screens/Messages/components/MessageInputEmbed.tsx b/src/screens/Messages/components/MessageInputEmbed.tsx index af6906dd91..d368f05b6b 100644 --- a/src/screens/Messages/components/MessageInputEmbed.tsx +++ b/src/screens/Messages/components/MessageInputEmbed.tsx @@ -30,7 +30,7 @@ import {ContentHider} from '#/components/moderation/ContentHider' import {PostAlerts} from '#/components/moderation/PostAlerts' import {RichText} from '#/components/RichText' import {Text} from '#/components/Typography' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' export function useMessageEmbed() { const route = @@ -114,7 +114,7 @@ export function MessageInputEmbed({ const {rt, record} = useMemo(() => { if ( post && - atp.dangerousIsType( + bsky.dangerousIsType( post.record, AppBskyFeedPost.isRecord, ) diff --git a/src/screens/Onboarding/StepFinished.tsx b/src/screens/Onboarding/StepFinished.tsx index 1e1c6aacd8..cd28f61389 100644 --- a/src/screens/Onboarding/StepFinished.tsx +++ b/src/screens/Onboarding/StepFinished.tsx @@ -49,7 +49,7 @@ import {News2_Stroke2_Corner0_Rounded as News} from '#/components/icons/News2' import {Trending2_Stroke2_Corner2_Rounded as Trending} from '#/components/icons/Trending2' import {Loader} from '#/components/Loader' import {Text} from '#/components/Typography' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' export function StepFinished() { const {_} = useLingui() @@ -213,7 +213,7 @@ export function StepFinished() { usedStarterPack: Boolean(starterPack), starterPackName: starterPack && - atp.dangerousIsType( + bsky.dangerousIsType( starterPack.record, AppBskyGraphStarterpack.isRecord, ) diff --git a/src/screens/Signup/index.tsx b/src/screens/Signup/index.tsx index 55367fa9e0..e82d0da1c0 100644 --- a/src/screens/Signup/index.tsx +++ b/src/screens/Signup/index.tsx @@ -26,7 +26,7 @@ import {Divider} from '#/components/Divider' import {LinearGradientBackground} from '#/components/LinearGradientBackground' import {InlineLinkText} from '#/components/Link' import {Text} from '#/components/Typography' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' export function Signup({onPressBack}: {onPressBack: () => void}) { const {_} = useLingui() @@ -96,7 +96,7 @@ export function Signup({onPressBack}: {onPressBack: () => void}) { scrollable> {showStarterPackCard && - atp.dangerousIsType( + bsky.dangerousIsType( starterPack.record, AppBskyGraphStarterpack.isRecord, ) ? ( diff --git a/src/screens/StarterPack/StarterPackLandingScreen.tsx b/src/screens/StarterPack/StarterPackLandingScreen.tsx index 919e7b5d44..2d9a919698 100644 --- a/src/screens/StarterPack/StarterPackLandingScreen.tsx +++ b/src/screens/StarterPack/StarterPackLandingScreen.tsx @@ -38,7 +38,7 @@ import {Default as ProfileCard} from '#/components/ProfileCard' import * as Prompt from '#/components/Prompt' import {RichText} from '#/components/RichText' import {Text} from '#/components/Typography' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' const AnimatedPressable = Animated.createAnimatedComponent(Pressable) @@ -87,7 +87,7 @@ export function LandingScreen({ // Just for types, this cannot be hit if ( - !atp.dangerousIsType( + !bsky.dangerousIsType( starterPack.record, AppBskyGraphStarterpack.isRecord, ) diff --git a/src/screens/StarterPack/StarterPackScreen.tsx b/src/screens/StarterPack/StarterPackScreen.tsx index 50ce7ba37b..ac61c153b3 100644 --- a/src/screens/StarterPack/StarterPackScreen.tsx +++ b/src/screens/StarterPack/StarterPackScreen.tsx @@ -66,7 +66,7 @@ import {ProfilesList} from '#/components/StarterPack/Main/ProfilesList' import {QrCodeDialog} from '#/components/StarterPack/QrCodeDialog' import {ShareDialog} from '#/components/StarterPack/ShareDialog' import {Text} from '#/components/Typography' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' type StarterPackScreeProps = NativeStackScreenProps< CommonNavigatorParams, @@ -389,7 +389,7 @@ function Header({ } if ( - !atp.dangerousIsType( + !bsky.dangerousIsType( record, AppBskyGraphStarterpack.isRecord, ) diff --git a/src/screens/StarterPack/Wizard/State.tsx b/src/screens/StarterPack/Wizard/State.tsx index b09d74a002..6c64add055 100644 --- a/src/screens/StarterPack/Wizard/State.tsx +++ b/src/screens/StarterPack/Wizard/State.tsx @@ -10,7 +10,7 @@ import {msg} from '@lingui/macro' import {STARTER_PACK_MAX_SIZE} from '#/lib/constants' import {useSession} from '#/state/session' import * as Toast from '#/view/com/util/Toast' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' const steps = ['Details', 'Profiles', 'Feeds'] as const type Step = (typeof steps)[number] @@ -21,7 +21,7 @@ type Action = | {type: 'SetCanNext'; canNext: boolean} | {type: 'SetName'; name: string} | {type: 'SetDescription'; description: string} - | {type: 'AddProfile'; profile: atp.profile.AnyProfileView} + | {type: 'AddProfile'; profile: bsky.profile.AnyProfileView} | {type: 'RemoveProfile'; profileDid: string} | {type: 'AddFeed'; feed: GeneratorView} | {type: 'RemoveFeed'; feedUri: string} @@ -33,7 +33,7 @@ interface State { currentStep: Step name?: string description?: string - profiles: atp.profile.AnyProfileView[] + profiles: bsky.profile.AnyProfileView[] feeds: GeneratorView[] processing: boolean error?: string diff --git a/src/screens/StarterPack/Wizard/StepProfiles.tsx b/src/screens/StarterPack/Wizard/StepProfiles.tsx index 0c0cafa2f9..8a9a891e1a 100644 --- a/src/screens/StarterPack/Wizard/StepProfiles.tsx +++ b/src/screens/StarterPack/Wizard/StepProfiles.tsx @@ -16,7 +16,7 @@ import {Loader} from '#/components/Loader' import {ScreenTransition} from '#/components/StarterPack/Wizard/ScreenTransition' import {WizardProfileCard} from '#/components/StarterPack/Wizard/WizardListCard' import {Text} from '#/components/Typography' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' function keyExtractor(item: AppBskyActorDefs.ProfileViewBasic) { return item?.did ?? '' @@ -51,7 +51,7 @@ export function StepProfiles({ const renderItem = ({ item, - }: ListRenderItemInfo) => { + }: ListRenderItemInfo) => { return ( ( + const record = bsky.dangerousIsType( post.record, AppBskyFeedPost.isRecord, ) diff --git a/src/state/cache/profile-shadow.ts b/src/state/cache/profile-shadow.ts index 1ce70045e8..adbff39198 100644 --- a/src/state/cache/profile-shadow.ts +++ b/src/state/cache/profile-shadow.ts @@ -3,7 +3,7 @@ import {QueryClient} from '@tanstack/react-query' import EventEmitter from 'eventemitter3' import {batchedUpdates} from '#/lib/batchedUpdates' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' import {findAllProfilesInQueryData as findAllProfilesInActorSearchQueryData} from '../queries/actor-search' import {findAllProfilesInQueryData as findAllProfilesInKnownFollowersQueryData} from '../queries/known-followers' import {findAllProfilesInQueryData as findAllProfilesInListMembersQueryData} from '../queries/list-members' @@ -30,13 +30,13 @@ export interface ProfileShadow { } const shadows: WeakMap< - atp.profile.AnyProfileView, + bsky.profile.AnyProfileView, Partial > = new WeakMap() const emitter = new EventEmitter() export function useProfileShadow< - TProfileView extends atp.profile.AnyProfileView, + TProfileView extends bsky.profile.AnyProfileView, >(profile: TProfileView): Shadow { const [shadow, setShadow] = useState(() => shadows.get(profile)) const [prevPost, setPrevPost] = useState(profile) @@ -69,7 +69,7 @@ export function useProfileShadow< * This is useful for when the profile is not guaranteed to be loaded yet. */ export function useMaybeProfileShadow< - TProfileView extends atp.profile.AnyProfileView, + TProfileView extends bsky.profile.AnyProfileView, >(profile?: TProfileView): Shadow | undefined { const [shadow, setShadow] = useState(() => profile ? shadows.get(profile) : undefined, @@ -116,7 +116,7 @@ export function updateProfileShadow( }) } -function mergeShadow( +function mergeShadow( profile: TProfileView, shadow: Partial, ): Shadow { @@ -138,7 +138,7 @@ function mergeShadow( function* findProfilesInCache( queryClient: QueryClient, did: string, -): Generator { +): Generator { yield* findAllProfilesInListMembersQueryData(queryClient, did) yield* findAllProfilesInMyBlockedAccountsQueryData(queryClient, did) yield* findAllProfilesInMyMutedAccountsQueryData(queryClient, did) diff --git a/src/state/queries/notifications/util.ts b/src/state/queries/notifications/util.ts index 339a341d0f..f6f53f58fe 100644 --- a/src/state/queries/notifications/util.ts +++ b/src/state/queries/notifications/util.ts @@ -14,7 +14,7 @@ import {QueryClient} from '@tanstack/react-query' import chunk from 'lodash.chunk' import {labelIsHideableOffense} from '#/lib/moderation' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' import {precacheProfile} from '../profile' import {FeedNotification, FeedPage, NotificationType} from './types' @@ -253,11 +253,11 @@ function getSubjectUri( return notif.uri } else if (type === 'post-like' || type === 'repost') { if ( - atp.dangerousIsType( + bsky.dangerousIsType( notif.record, AppBskyFeedRepost.isRecord, ) || - atp.dangerousIsType( + bsky.dangerousIsType( notif.record, AppBskyFeedLike.isRecord, ) diff --git a/src/state/queries/post-thread.ts b/src/state/queries/post-thread.ts index ad82b513cb..b1cd626cf5 100644 --- a/src/state/queries/post-thread.ts +++ b/src/state/queries/post-thread.ts @@ -18,7 +18,7 @@ import { findAllProfilesInQueryData as findAllProfilesInSearchQueryData, } from '#/state/queries/search-posts' import {useAgent} from '#/state/session' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' import { findAllPostsInQueryData as findAllPostsInNotifsQueryData, findAllProfilesInQueryData as findAllProfilesInNotifsQueryData, @@ -333,7 +333,7 @@ function responseToThreadNodes( ): ThreadNode { if ( AppBskyFeedDefs.isThreadViewPost(node) && - atp.dangerousIsType( + bsky.dangerousIsType( node.post.record, AppBskyFeedPost.isRecord, ) diff --git a/src/state/queries/profile.ts b/src/state/queries/profile.ts index b50c17f93e..fac1fc8c12 100644 --- a/src/state/queries/profile.ts +++ b/src/state/queries/profile.ts @@ -29,7 +29,7 @@ import { useUnstableProfileViewCache, } from '#/state/queries/unstable-profile-cache' import * as userActionHistory from '#/state/userActionHistory' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' import {updateProfileShadow} from '../cache/profile-shadow' import {useAgent, useSession} from '../session' import { @@ -225,7 +225,7 @@ export function useProfileUpdateMutation() { } export function useProfileFollowMutationQueue( - profile: Shadow, + profile: Shadow, logContext: LogEvents['profile:follow']['logContext'] & LogEvents['profile:follow']['logContext'], ) { @@ -299,7 +299,7 @@ export function useProfileFollowMutationQueue( function useProfileFollowMutation( logContext: LogEvents['profile:follow']['logContext'], - profile: Shadow, + profile: Shadow, ) { const {currentAccount} = useSession() const agent = useAgent() @@ -340,7 +340,7 @@ function useProfileUnfollowMutation( } export function useProfileMuteMutationQueue( - profile: Shadow, + profile: Shadow, ) { const queryClient = useQueryClient() const did = profile.did @@ -415,7 +415,7 @@ function useProfileUnmuteMutation() { } export function useProfileBlockMutationQueue( - profile: Shadow, + profile: Shadow, ) { const queryClient = useQueryClient() const did = profile.did diff --git a/src/state/queries/starter-packs.ts b/src/state/queries/starter-packs.ts index ec935836d3..02da3f5a1b 100644 --- a/src/state/queries/starter-packs.ts +++ b/src/state/queries/starter-packs.ts @@ -29,7 +29,7 @@ import {invalidateActorStarterPacksQuery} from '#/state/queries/actor-starter-pa import {STALE} from '#/state/queries/index' import {invalidateListMembersQuery} from '#/state/queries/list-members' import {useAgent} from '#/state/session' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' const RQKEY_ROOT = 'starter-pack' const RQKEY = ({ @@ -94,7 +94,7 @@ export async function invalidateStarterPack({ interface UseCreateStarterPackMutationParams { name: string description?: string - profiles: atp.profile.AnyProfileView[] + profiles: bsky.profile.AnyProfileView[] feeds?: AppBskyFeedDefs.GeneratorView[] } diff --git a/src/state/queries/unstable-profile-cache.ts b/src/state/queries/unstable-profile-cache.ts index 7ffbfade4a..4ac5001b7d 100644 --- a/src/state/queries/unstable-profile-cache.ts +++ b/src/state/queries/unstable-profile-cache.ts @@ -1,7 +1,7 @@ import {useCallback} from 'react' import {QueryClient, useQueryClient} from '@tanstack/react-query' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' const unstableProfileViewCacheQueryKeyRoot = 'unstableProfileViewCache' export const unstableProfileViewCacheQueryKey = (didOrHandle: string) => [ @@ -17,7 +17,7 @@ export const unstableProfileViewCacheQueryKey = (didOrHandle: string) => [ */ export function unstableCacheProfileView( queryClient: QueryClient, - profile: atp.profile.AnyProfileView, + profile: bsky.profile.AnyProfileView, ) { queryClient.setQueryData( unstableProfileViewCacheQueryKey(profile.handle), @@ -41,7 +41,7 @@ export function useUnstableProfileViewCache() { const qc = useQueryClient() const getUnstableProfile = useCallback( (didOrHandle: string) => { - return qc.getQueryData( + return qc.getQueryData( unstableProfileViewCacheQueryKey(didOrHandle), ) }, diff --git a/src/state/queries/util.ts b/src/state/queries/util.ts index e299f013db..71d185bec7 100644 --- a/src/state/queries/util.ts +++ b/src/state/queries/util.ts @@ -8,7 +8,7 @@ import { } from '@atproto/api' import {InfiniteData, QueryClient, QueryKey} from '@tanstack/react-query' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' export async function truncateAndInvalidate( queryClient: QueryClient, @@ -47,7 +47,7 @@ export function getEmbeddedPost( v: unknown, ): AppBskyEmbedRecord.ViewRecord | undefined { if ( - atp.dangerousIsType(v, AppBskyEmbedRecord.isView) + bsky.dangerousIsType(v, AppBskyEmbedRecord.isView) ) { if ( AppBskyEmbedRecord.isViewRecord(v.record) && @@ -57,7 +57,7 @@ export function getEmbeddedPost( } } if ( - atp.dangerousIsType( + bsky.dangerousIsType( v, AppBskyEmbedRecordWithMedia.isView, ) diff --git a/src/types/atproto/index.ts b/src/types/bsky/index.ts similarity index 87% rename from src/types/atproto/index.ts rename to src/types/bsky/index.ts index 5792770a08..2b9ab5b45e 100644 --- a/src/types/atproto/index.ts +++ b/src/types/bsky/index.ts @@ -1,5 +1,5 @@ -export * as profile from '#/types/atproto/profile' -export * as starterPack from '#/types/atproto/starterPack' +export * as profile from '#/types/bsky/profile' +export * as starterPack from '#/types/bsky/starterPack' /** * Use sparingly, and only when you know it's safe to do so. diff --git a/src/types/atproto/post.ts b/src/types/bsky/post.ts similarity index 100% rename from src/types/atproto/post.ts rename to src/types/bsky/post.ts diff --git a/src/types/atproto/profile.ts b/src/types/bsky/profile.ts similarity index 100% rename from src/types/atproto/profile.ts rename to src/types/bsky/profile.ts diff --git a/src/types/atproto/starterPack.ts b/src/types/bsky/starterPack.ts similarity index 100% rename from src/types/atproto/starterPack.ts rename to src/types/bsky/starterPack.ts diff --git a/src/view/com/lists/ListMembers.tsx b/src/view/com/lists/ListMembers.tsx index c8ecfc057a..31d2b5fb5c 100644 --- a/src/view/com/lists/ListMembers.tsx +++ b/src/view/com/lists/ListMembers.tsx @@ -11,7 +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 * as bsky from '#/types/bsky' import {ProfileCard} from '../profile/ProfileCard' import {ErrorMessage} from '../util/error/ErrorMessage' import {Button} from '../util/forms/Button' @@ -117,7 +117,7 @@ export function ListMembers({ }, [fetchNextPage]) const onPressEditMembership = React.useCallback( - (profile: atp.profile.AnyProfileView) => { + (profile: bsky.profile.AnyProfileView) => { openModal({ name: 'user-add-remove-lists', subject: profile.did, @@ -132,7 +132,7 @@ export function ListMembers({ // = const renderMemberButton = React.useCallback( - (profile: atp.profile.AnyProfileView) => { + (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 186d054fca..84694fe3b8 100644 --- a/src/view/com/notifications/NotificationFeedItem.tsx +++ b/src/view/com/notifications/NotificationFeedItem.tsx @@ -58,7 +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 atp from '#/types/atproto' +import * as bsky from '#/types/bsky' import {FeedSourceCard} from '../feeds/FeedSourceCard' import {Post} from '../post/Post' import {Link, TextLink} from '../util/Link' @@ -265,7 +265,7 @@ let NotificationFeedItem = ({ if ( item.notification.author.viewer?.following && - atp.dangerousIsType( + bsky.dangerousIsType( item.notification.record, AppBskyGraphFollow.isRecord, ) @@ -722,7 +722,7 @@ function AdditionalPostText({post}: {post?: AppBskyFeedDefs.PostView}) { const pal = usePalette('default') if ( post && - atp.dangerousIsType( + bsky.dangerousIsType( post?.record, AppBskyFeedPost.isRecord, ) diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx index d88ec66880..00d0dc9ed9 100644 --- a/src/view/com/post-thread/PostThreadItem.tsx +++ b/src/view/com/post-thread/PostThreadItem.tsx @@ -58,7 +58,7 @@ import {RichText} from '#/components/RichText' import {SubtleWebHover} from '#/components/SubtleWebHover' import {Text} from '#/components/Typography' import {WhoCanReply} from '#/components/WhoCanReply' -import * as atp from '#/types/atproto' +import * as bsky from '#/types/bsky' export function PostThreadItem({ post, @@ -786,7 +786,7 @@ function BackdatedPostIndicator({post}: {post: AppBskyFeedDefs.PostView}) { const control = Prompt.usePromptControl() const indexedAt = new Date(post.indexedAt) - const createdAt = atp.dangerousIsType( + const createdAt = bsky.dangerousIsType( post.record, AppBskyFeedPost.isRecord, ) diff --git a/src/view/com/posts/PostFeedItem.tsx b/src/view/com/posts/PostFeedItem.tsx index 6aa1642db0..5dc8690fa3 100644 --- a/src/view/com/posts/PostFeedItem.tsx +++ b/src/view/com/posts/PostFeedItem.tsx @@ -47,7 +47,7 @@ import {AppModerationCause} from '#/components/Pills' import {ProfileHoverCard} from '#/components/ProfileHoverCard' import {RichText} from '#/components/RichText' import {SubtleWebHover} from '#/components/SubtleWebHover' -import * as atp from '#/types/atproto' +import * as atp from '#/types/bsky' import {Link, TextLink, TextLinkOnWebOnly} from '../util/Link' import {AviFollowButton} from './AviFollowButton' diff --git a/src/view/com/profile/FollowButton.tsx b/src/view/com/profile/FollowButton.tsx index 4381d974b6..656ed914af 100644 --- a/src/view/com/profile/FollowButton.tsx +++ b/src/view/com/profile/FollowButton.tsx @@ -4,7 +4,7 @@ import {useLingui} from '@lingui/react' import {Shadow} from '#/state/cache/types' import {useProfileFollowMutationQueue} from '#/state/queries/profile' -import * as atp from '#/types/atproto' +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 + profile: Shadow labelStyle?: StyleProp logContext: 'ProfileCard' | 'StarterPackProfilesList' onFollow?: () => void diff --git a/src/view/com/profile/ProfileCard.tsx b/src/view/com/profile/ProfileCard.tsx index 6d9796fb49..4eb5d4859c 100644 --- a/src/view/com/profile/ProfileCard.tsx +++ b/src/view/com/profile/ProfileCard.tsx @@ -24,7 +24,7 @@ import { shouldShowKnownFollowers, } from '#/components/KnownFollowers' import * as Pills from '#/components/Pills' -import * as atp from '#/types/atproto' +import * as atp from '#/types/bsky' import {Link} from '../util/Link' import {Text} from '../util/text/Text' import {PreviewableUserAvatar} from '../util/UserAvatar' diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index 7c24cab9f2..934e8f50cc 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -31,7 +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 atp from '#/types/atproto' +import * as bsky from '#/types/bsky' import {openCamera, openCropper, openPicker} from '../../../lib/media/picker' export type UserAvatarType = 'user' | 'algo' | 'list' | 'labeler' @@ -56,7 +56,7 @@ interface EditableUserAvatarProps extends BaseUserAvatarProps { interface PreviewableUserAvatarProps extends BaseUserAvatarProps { moderation?: ModerationUI - profile: atp.profile.AnyProfileView + 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 6622ff98a2..e283a2eec1 100644 --- a/src/view/com/util/post-embeds/QuoteEmbed.tsx +++ b/src/view/com/util/post-embeds/QuoteEmbed.tsx @@ -36,7 +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 atp from '#/types/atproto' +import * as bsky from '#/types/bsky' import {ContentHider} from '../../../../components/moderation/ContentHider' import {PostAlerts} from '../../../../components/moderation/PostAlerts' import {Link} from '../Link' @@ -173,7 +173,7 @@ export function QuoteEmbed({ const richText = React.useMemo(() => { if ( - !atp.dangerousIsType( + !bsky.dangerousIsType( quote.record, AppBskyFeedPost.isRecord, ) From 119f56bd0096929f37e76ef48cad47b426e86362 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 6 Feb 2025 10:43:09 -0600 Subject: [PATCH 141/142] Add validate util --- package.json | 1 + src/components/StarterPack/QrCodeDialog.tsx | 10 ++--- src/lib/api/feed-manip.ts | 8 ++-- src/screens/Settings/components/PwiOptOut.tsx | 8 ++-- src/screens/StarterPack/Wizard/State.tsx | 8 +--- src/state/queries/postgate/index.ts | 4 +- src/state/queries/starter-packs.ts | 3 +- src/state/queries/threadgate/index.ts | 4 +- src/state/queries/threadgate/util.ts | 5 ++- src/types/bsky/index.ts | 38 +++++++++++++++---- src/view/com/post/Post.tsx | 4 +- yarn.lock | 22 +++++------ 12 files changed, 68 insertions(+), 47 deletions(-) diff --git a/package.json b/package.json index 501beaefa0..780917e370 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ }, "dependencies": { "@atproto/api": "0.14.0-next.6", + "@atproto/lexicon": "0.4.6-next.5", "@bitdrift/react-native": "^0.6.2", "@braintree/sanitize-url": "^6.0.2", "@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet", diff --git a/src/components/StarterPack/QrCodeDialog.tsx b/src/components/StarterPack/QrCodeDialog.tsx index 63d58a0f44..43d8b72dad 100644 --- a/src/components/StarterPack/QrCodeDialog.tsx +++ b/src/components/StarterPack/QrCodeDialog.tsx @@ -4,11 +4,7 @@ import type ViewShot from 'react-native-view-shot' import {requestMediaLibraryPermissionsAsync} from 'expo-image-picker' import {createAssetAsync} from 'expo-media-library' import * as Sharing from 'expo-sharing' -import { - AppBskyGraphDefs, - AppBskyGraphStarterpack, - asPredicate, -} from '@atproto/api' +import {AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -22,6 +18,7 @@ import * as Dialog from '#/components/Dialog' import {DialogControlProps} from '#/components/Dialog' import {Loader} from '#/components/Loader' import {QrCode} from '#/components/StarterPack/QrCode' +import * as bsky from '#/types/bsky' export function QrCodeDialog({ starterPack, @@ -82,8 +79,9 @@ export function QrCodeDialog({ setIsProcessing(true) if ( - !asPredicate(AppBskyGraphStarterpack.validateRecord)( + !bsky.validate( starterPack.record, + AppBskyGraphStarterpack.validateRecord, ) ) { return diff --git a/src/lib/api/feed-manip.ts b/src/lib/api/feed-manip.ts index ed43f362ea..a1b2e2bc90 100644 --- a/src/lib/api/feed-manip.ts +++ b/src/lib/api/feed-manip.ts @@ -4,9 +4,9 @@ import { AppBskyEmbedRecordWithMedia, AppBskyFeedDefs, AppBskyFeedPost, - asPredicate, } from '@atproto/api' +import * as bsky from '#/types/bsky' import {isPostInLanguage} from '../../locale/helpers' import {FALLBACK_MARKER_POST} from './feed/home' import {ReasonFeedSource} from './feed/types' @@ -68,7 +68,7 @@ export class FeedViewPostsSlice { } if ( !AppBskyFeedPost.isRecord(post.record) || - !asPredicate(AppBskyFeedPost.validateRecord)(post.record) + !bsky.validate(post.record, AppBskyFeedPost.validateRecord) ) { return } @@ -100,7 +100,7 @@ export class FeedViewPostsSlice { if ( !AppBskyFeedDefs.isPostView(parent) || !AppBskyFeedPost.isRecord(parent.record) || - !asPredicate(AppBskyFeedPost.validateRecord)(parent.record) + !bsky.validate(parent.record, AppBskyFeedPost.validateRecord) ) { this.isOrphan = true return @@ -142,7 +142,7 @@ export class FeedViewPostsSlice { if ( !AppBskyFeedDefs.isPostView(root) || !AppBskyFeedPost.isRecord(root.record) || - !asPredicate(AppBskyFeedPost.validateRecord)(root.record) + !bsky.validate(root.record, AppBskyFeedPost.validateRecord) ) { this.isOrphan = true return diff --git a/src/screens/Settings/components/PwiOptOut.tsx b/src/screens/Settings/components/PwiOptOut.tsx index e0581da7fa..e585149763 100644 --- a/src/screens/Settings/components/PwiOptOut.tsx +++ b/src/screens/Settings/components/PwiOptOut.tsx @@ -1,6 +1,6 @@ import React from 'react' import {View} from 'react-native' -import {$Typed, asPredicate,ComAtprotoLabelDefs} from '@atproto/api' +import {$Typed, ComAtprotoLabelDefs} from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -12,6 +12,7 @@ import {useSession} from '#/state/session' import {atoms as a, useTheme} from '#/alf' import * as Toggle from '#/components/forms/Toggle' import {Text} from '#/components/Typography' +import * as bsky from '#/types/bsky' export function PwiOptOut() { const t = useTheme() @@ -33,9 +34,10 @@ export function PwiOptOut() { profile, updates: existing => { // create labels attr if needed - const labels: $Typed = asPredicate( + const labels: $Typed = bsky.validate( + existing.labels, ComAtprotoLabelDefs.validateSelfLabels, - )(existing.labels) + ) ? existing.labels : { $type: 'com.atproto.label.defs#selfLabels', diff --git a/src/screens/StarterPack/Wizard/State.tsx b/src/screens/StarterPack/Wizard/State.tsx index 6c64add055..baf0195d82 100644 --- a/src/screens/StarterPack/Wizard/State.tsx +++ b/src/screens/StarterPack/Wizard/State.tsx @@ -1,9 +1,5 @@ import React from 'react' -import { - AppBskyGraphDefs, - AppBskyGraphStarterpack, - asPredicate, -} from '@atproto/api' +import {AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api' import {GeneratorView} from '@atproto/api/dist/client/types/app/bsky/feed/defs' import {msg} from '@lingui/macro' @@ -128,7 +124,7 @@ export function Provider({ const createInitialState = (): State => { if ( starterPack && - asPredicate(AppBskyGraphStarterpack.validateRecord)(starterPack.record) + bsky.validate(starterPack.record, AppBskyGraphStarterpack.validateRecord) ) { return { canNext: true, diff --git a/src/state/queries/postgate/index.ts b/src/state/queries/postgate/index.ts index 6605ab8e68..346e7bfe29 100644 --- a/src/state/queries/postgate/index.ts +++ b/src/state/queries/postgate/index.ts @@ -4,7 +4,6 @@ import { AppBskyEmbedRecordWithMedia, AppBskyFeedDefs, AppBskyFeedPostgate, - asPredicate, AtUri, BskyAgent, } from '@atproto/api' @@ -22,6 +21,7 @@ import { POSTGATE_COLLECTION, } from '#/state/queries/postgate/util' import {useAgent} from '#/state/session' +import * as bsky from '#/types/bsky' export async function getPostgateRecord({ agent, @@ -63,7 +63,7 @@ export async function getPostgateRecord({ if ( data.value && - asPredicate(AppBskyFeedPostgate.validateRecord)(data.value) + bsky.validate(data.value, AppBskyFeedPostgate.validateRecord) ) { return data.value } else { diff --git a/src/state/queries/starter-packs.ts b/src/state/queries/starter-packs.ts index 02da3f5a1b..64ebbd0e5a 100644 --- a/src/state/queries/starter-packs.ts +++ b/src/state/queries/starter-packs.ts @@ -4,7 +4,6 @@ import { AppBskyGraphGetStarterPack, AppBskyGraphStarterpack, AppBskyRichtextFacet, - asPredicate, AtUri, BskyAgent, RichText, @@ -369,7 +368,7 @@ export async function precacheStarterPack( starterPackView = starterPack } else if ( AppBskyGraphDefs.isStarterPackViewBasic(starterPack) && - asPredicate(AppBskyGraphStarterpack.validateRecord)(starterPack.record) + bsky.validate(starterPack.record, AppBskyGraphStarterpack.validateRecord) ) { const listView: AppBskyGraphDefs.ListViewBasic = { uri: starterPack.record.list, diff --git a/src/state/queries/threadgate/index.ts b/src/state/queries/threadgate/index.ts index 0eb1e72979..478658fe88 100644 --- a/src/state/queries/threadgate/index.ts +++ b/src/state/queries/threadgate/index.ts @@ -2,7 +2,6 @@ import { AppBskyFeedDefs, AppBskyFeedGetPostThread, AppBskyFeedThreadgate, - asPredicate, AtUri, BskyAgent, } from '@atproto/api' @@ -21,6 +20,7 @@ import { } from '#/state/queries/threadgate/util' import {useAgent} from '#/state/session' import {useThreadgateHiddenReplyUrisAPI} from '#/state/threadgate-hidden-replies' +import * as bsky from '#/types/bsky' export * from '#/state/queries/threadgate/types' export * from '#/state/queries/threadgate/util' @@ -141,7 +141,7 @@ export async function getThreadgateRecord({ if ( data.value && - asPredicate(AppBskyFeedThreadgate.validateRecord)(data.value) + bsky.validate(data.value, AppBskyFeedThreadgate.validateRecord) ) { return data.value } else { diff --git a/src/state/queries/threadgate/util.ts b/src/state/queries/threadgate/util.ts index 452fc84c79..1e70e2e31f 100644 --- a/src/state/queries/threadgate/util.ts +++ b/src/state/queries/threadgate/util.ts @@ -1,6 +1,7 @@ -import {AppBskyFeedDefs, AppBskyFeedThreadgate, asPredicate} from '@atproto/api' +import {AppBskyFeedDefs, AppBskyFeedThreadgate} from '@atproto/api' import {ThreadgateAllowUISetting} from '#/state/queries/threadgate/types' +import * as bsky from '#/types/bsky' export function threadgateViewToAllowUISetting( threadgateView: AppBskyFeedDefs.ThreadgateView | undefined, @@ -8,7 +9,7 @@ export function threadgateViewToAllowUISetting( // Validate the record for clarity, since backwards compat code is a little confusing const threadgate = threadgateView && - asPredicate(AppBskyFeedThreadgate.validateRecord)(threadgateView.record) + bsky.validate(threadgateView.record, AppBskyFeedThreadgate.validateRecord) ? threadgateView.record : undefined return threadgateRecordToAllowUISetting(threadgate) diff --git a/src/types/bsky/index.ts b/src/types/bsky/index.ts index 2b9ab5b45e..7354e5bcd8 100644 --- a/src/types/bsky/index.ts +++ b/src/types/bsky/index.ts @@ -1,19 +1,22 @@ +import {asPredicate} from '@atproto/api' +import {ValidationResult} from '@atproto/lexicon' + export * as profile from '#/types/bsky/profile' export * as starterPack from '#/types/bsky/starterPack' /** - * Use sparingly, and only when you know it's safe to do so. + * Fast type checking without full schema validation, for use with data we + * trust, or for non-critical path use cases. Why? Our SDK's `is*` identity + * utils do not assert the type of the entire object, only the `$type` string. * - * Our SDK's `is*` identity utils do not assert the type of the entire object, - * and although the `isValid*` utils do, they also fully validate the object - * shape, which has a performance cost. This util allows us to prescribe the - * type we expect, while only checking the `$type` value of the record. + * For full validation of the object schema, use the `validate` export from + * this file. * * Usage: * ```ts - * import * as atp from '#/types/atproto' + * import * as bsky from '#/types/bsky' * - * if (atp.dangerousIsType(item, AppBskyFeedPost.isRecord)) { + * if (bsky.dangerousIsType(item, AppBskyFeedPost.isRecord)) { * // `item` has type `$Typed` here * } * ``` @@ -24,3 +27,24 @@ export function dangerousIsType( ): record is R { return identity(record) } + +/** + * Fully validates the object schema, which as a performance cost. + * + * For faster checks with data we trust, like that from our app view, use the + * `dangerousIsType` export from this same file. + * + * Usage: + * ```ts + * import * as bsky from '#/types/bsky' + * + * if (bsky.validate(item, AppBskyFeedPost.validateRecord)) { + * // `item` has type `$Typed` here + * } + */ +export function validate( + record: unknown, + identity: (v: unknown) => ValidationResult, +): record is R { + return asPredicate(identity)(record) +} diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx index 07e374692c..2645237ad3 100644 --- a/src/view/com/post/Post.tsx +++ b/src/view/com/post/Post.tsx @@ -3,7 +3,6 @@ import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native' import { AppBskyFeedDefs, AppBskyFeedPost, - asPredicate, AtUri, ModerationDecision, RichText as RichTextAPI, @@ -29,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' @@ -54,7 +54,7 @@ export function Post({ const moderationOpts = useModerationOpts() const record = useMemo( () => - asPredicate(AppBskyFeedPost.validateRecord)(post.record) + bsky.validate(post.record, AppBskyFeedPost.validateRecord) ? post.record : undefined, [post], diff --git a/yarn.lock b/yarn.lock index c126332323..4eeb36bee7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -282,6 +282,17 @@ multiformats "^9.9.0" zod "^3.23.8" +"@atproto/lexicon@0.4.6-next.5", "@atproto/lexicon@^0.4.6-next.5": + version "0.4.6-next.5" + resolved "https://registry.yarnpkg.com/@atproto/lexicon/-/lexicon-0.4.6-next.5.tgz#433a941cf8902afec15135f70cf2cbed37c35406" + integrity sha512-Id1atQ1rZ3dUGAUyBcauD+zs5lGHSmoAlC1Kwb2DEvkaWMv3oTXUjtdQxyb0/Kz4YaFI+nxLLRH9NBO+BipG+w== + dependencies: + "@atproto/common-web" "^0.3.2" + "@atproto/syntax" "^0.3.1" + iso-datestring-validator "^2.2.2" + multiformats "^9.9.0" + zod "^3.23.8" + "@atproto/lexicon@^0.4.4": version "0.4.4" resolved "https://registry.yarnpkg.com/@atproto/lexicon/-/lexicon-0.4.4.tgz#0d97314bb57b693b76f2495fa5e02872469dd93a" @@ -304,17 +315,6 @@ multiformats "^9.9.0" zod "^3.23.8" -"@atproto/lexicon@^0.4.6-next.5": - version "0.4.6-next.5" - resolved "https://registry.yarnpkg.com/@atproto/lexicon/-/lexicon-0.4.6-next.5.tgz#433a941cf8902afec15135f70cf2cbed37c35406" - integrity sha512-Id1atQ1rZ3dUGAUyBcauD+zs5lGHSmoAlC1Kwb2DEvkaWMv3oTXUjtdQxyb0/Kz4YaFI+nxLLRH9NBO+BipG+w== - dependencies: - "@atproto/common-web" "^0.3.2" - "@atproto/syntax" "^0.3.1" - iso-datestring-validator "^2.2.2" - multiformats "^9.9.0" - zod "^3.23.8" - "@atproto/oauth-provider@^0.2.10": version "0.2.10" resolved "https://registry.yarnpkg.com/@atproto/oauth-provider/-/oauth-provider-0.2.10.tgz#f9820d7f82c33d3b74e81a75873f50e1e654b901" From bf5f604ac1951a0efca4d363603fee50f390fa88 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 6 Feb 2025 10:43:17 -0600 Subject: [PATCH 142/142] Fix type error --- src/components/dms/MessagesListHeader.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/dms/MessagesListHeader.tsx b/src/components/dms/MessagesListHeader.tsx index 39e8f69055..7c35c30ba4 100644 --- a/src/components/dms/MessagesListHeader.tsx +++ b/src/components/dms/MessagesListHeader.tsx @@ -17,6 +17,7 @@ import {sanitizeDisplayName} from '#/lib/strings/display-names' import {isWeb} from '#/platform/detection' import {Shadow} from '#/state/cache/profile-shadow' import {isConvoActive, useConvo} from '#/state/messages/convo' +import {ConvoItem} from '#/state/messages/convo/types' import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar' import {atoms as a, useBreakpoints, useTheme, web} from '#/alf' import {ConvoMenu} from '#/components/dms/ConvoMenu' @@ -159,7 +160,8 @@ function HeaderReady({ // @ts-ignore findLast is polyfilled - esb const latestMessageFromOther = convoState.items.findLast( - item => item.type === 'message' && item.message.sender.did === profile.did, + (item: ConvoItem) => + item.type === 'message' && item.message.sender.did === profile.did, ) const latestReportableMessage =