diff --git a/lexicons.json b/lexicons.json index 52cd43df09..ac33ff919f 100644 --- a/lexicons.json +++ b/lexicons.json @@ -123,6 +123,10 @@ "app.bsky.notification.unregisterPush", "app.bsky.notification.updateSeen", "app.bsky.richtext.facet", + "app.bsky.unspecced.getSuggestedOnboardingUsers", + "app.bsky.unspecced.getSuggestedUsersForDiscover", + "app.bsky.unspecced.getSuggestedUsersForExplore", + "app.bsky.unspecced.getSuggestedUsersForSeeMore", "app.bsky.video.defs", "app.bsky.video.getJobStatus", "app.bsky.video.getUploadLimits", @@ -273,6 +277,8 @@ "com.atproto.sync.notifyOfUpdate", "com.atproto.sync.requestCrawl", "com.atproto.sync.subscribeRepos", + "com.atproto.temp.checkHandleAvailability", + "com.atproto.temp.checkSignupQueue", "com.germnetwork.declaration" ], "resolutions": { @@ -800,6 +806,10 @@ "uri": "at://did:plc:placeholder00000000000000000000/com.atproto.lexicon.schema/app.bsky.unspecced.getSuggestedFeedsSkeleton", "cid": "bafyreihqvsdre7oxhlpl7yucsmpdupwakipyzsu2gjlkbufgmklcgr5cbq" }, + "app.bsky.unspecced.getSuggestedOnboardingUsers": { + "uri": "at://did:plc:placeholder00000000000000000000/com.atproto.lexicon.schema/app.bsky.unspecced.getSuggestedOnboardingUsers", + "cid": "bafyreieot3hdk6h2enuivlp6m2jivd2y4npwbr4h7nsb3kutvnmtpkubm4" + }, "app.bsky.unspecced.getSuggestedStarterPacks": { "uri": "at://did:plc:placeholder00000000000000000000/com.atproto.lexicon.schema/app.bsky.unspecced.getSuggestedStarterPacks", "cid": "bafyreih34c76u3vbjaaukyojpsrljslmnptzpnydizyfrjtedzmwosmawy" @@ -812,6 +822,18 @@ "uri": "at://did:plc:placeholder00000000000000000000/com.atproto.lexicon.schema/app.bsky.unspecced.getSuggestedUsers", "cid": "bafyreib5qavwbqignxipudnk5jzs2inlkjxosckpxakorbk3erlscfn6ba" }, + "app.bsky.unspecced.getSuggestedUsersForDiscover": { + "uri": "at://did:plc:placeholder00000000000000000000/com.atproto.lexicon.schema/app.bsky.unspecced.getSuggestedUsersForDiscover", + "cid": "bafyreienm4jci3ri5umqmdyycpyhtwjbteynqx54tyfjdrilzg6kqr65dm" + }, + "app.bsky.unspecced.getSuggestedUsersForExplore": { + "uri": "at://did:plc:placeholder00000000000000000000/com.atproto.lexicon.schema/app.bsky.unspecced.getSuggestedUsersForExplore", + "cid": "bafyreidje2onbwlnhm6st54evtxvvsc5n3al4vxq67maah24a2hvwvsd2m" + }, + "app.bsky.unspecced.getSuggestedUsersForSeeMore": { + "uri": "at://did:plc:placeholder00000000000000000000/com.atproto.lexicon.schema/app.bsky.unspecced.getSuggestedUsersForSeeMore", + "cid": "bafyreidg6zyy4x2cskf7jfdhlmn4nps6ug7tzqhckpx3s264xlxrh5djji" + }, "app.bsky.unspecced.getSuggestedUsersSkeleton": { "uri": "at://did:plc:placeholder00000000000000000000/com.atproto.lexicon.schema/app.bsky.unspecced.getSuggestedUsersSkeleton", "cid": "bafyreibvcocfbsxbf2s2rzuvcovkoyq6m7yz3csxrd6mdeoiwmkjqucxke" @@ -1456,6 +1478,14 @@ "uri": "at://did:plc:6msi3pj7krzih5qxqtryxlzw/com.atproto.lexicon.schema/com.atproto.sync.subscribeRepos", "cid": "bafyreic6fm5atifiaq67u44dtxc3ufjbq3z7yysryjrzrw37hkb32yajbi" }, + "com.atproto.temp.checkHandleAvailability": { + "uri": "at://did:plc:placeholder00000000000000000000/com.atproto.lexicon.schema/com.atproto.temp.checkHandleAvailability", + "cid": "bafyreifanpe7ixmxampsbl3oaftbo24vzhe5pcunhf3xdsmrmgrgkq5ziq" + }, + "com.atproto.temp.checkSignupQueue": { + "uri": "at://did:plc:placeholder00000000000000000000/com.atproto.lexicon.schema/com.atproto.temp.checkSignupQueue", + "cid": "bafyreignao6slhwqr5kqdiey243oy5wmewfkz4vzseoypdxzoyakwen7bm" + }, "com.germnetwork.declaration": { "uri": "at://did:plc:qyqmmncrm6qx33kpy7vqndik/com.atproto.lexicon.schema/com.germnetwork.declaration", "cid": "bafyreiekwjmxshje655olra4mata7npso7bbgytc4fop77ycjtrbewwi3y" diff --git a/lexicons/app/bsky/unspecced/getSuggestedOnboardingUsers.json b/lexicons/app/bsky/unspecced/getSuggestedOnboardingUsers.json new file mode 100644 index 0000000000..24e45566ef --- /dev/null +++ b/lexicons/app/bsky/unspecced/getSuggestedOnboardingUsers.json @@ -0,0 +1,49 @@ +{ + "lexicon": 1, + "id": "app.bsky.unspecced.getSuggestedOnboardingUsers", + "defs": { + "main": { + "type": "query", + "description": "Get a list of suggested users for onboarding", + "parameters": { + "type": "params", + "properties": { + "category": { + "type": "string", + "description": "Category of users to get suggestions for." + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 50, + "default": 25 + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["actors"], + "properties": { + "actors": { + "type": "array", + "items": { + "type": "ref", + "ref": "app.bsky.actor.defs#profileView" + } + }, + "recId": { + "type": "string", + "description": "DEPRECATED: use recIdStr instead." + }, + "recIdStr": { + "type": "string", + "description": "Snowflake for this recommendation, use when submitting recommendation events." + } + } + } + } + } + } +} diff --git a/lexicons/app/bsky/unspecced/getSuggestedUsersForDiscover.json b/lexicons/app/bsky/unspecced/getSuggestedUsersForDiscover.json new file mode 100644 index 0000000000..7d0f289d12 --- /dev/null +++ b/lexicons/app/bsky/unspecced/getSuggestedUsersForDiscover.json @@ -0,0 +1,41 @@ +{ + "lexicon": 1, + "id": "app.bsky.unspecced.getSuggestedUsersForDiscover", + "defs": { + "main": { + "type": "query", + "description": "Get a list of suggested users for the Discover page", + "parameters": { + "type": "params", + "properties": { + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 50, + "default": 25 + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["actors"], + "properties": { + "actors": { + "type": "array", + "items": { + "type": "ref", + "ref": "app.bsky.actor.defs#profileView" + } + }, + "recIdStr": { + "type": "string", + "description": "Snowflake for this recommendation, use when submitting recommendation events." + } + } + } + } + } + } +} diff --git a/lexicons/app/bsky/unspecced/getSuggestedUsersForDiscoverSkeleton.json b/lexicons/app/bsky/unspecced/getSuggestedUsersForDiscoverSkeleton.json new file mode 100644 index 0000000000..7f017ca5e6 --- /dev/null +++ b/lexicons/app/bsky/unspecced/getSuggestedUsersForDiscoverSkeleton.json @@ -0,0 +1,46 @@ +{ + "lexicon": 1, + "id": "app.bsky.unspecced.getSuggestedUsersForDiscoverSkeleton", + "defs": { + "main": { + "type": "query", + "description": "Get a skeleton of suggested users for the Discover page. Intended to be called and hydrated by app.bsky.unspecced.getSuggestedUsersForDiscover", + "parameters": { + "type": "params", + "properties": { + "viewer": { + "type": "string", + "format": "did", + "description": "DID of the account making the request (not included for public/unauthenticated queries)." + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 50, + "default": 25 + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["dids"], + "properties": { + "dids": { + "type": "array", + "items": { + "type": "string", + "format": "did" + } + }, + "recIdStr": { + "type": "string", + "description": "Snowflake for this recommendation, use when submitting recommendation events." + } + } + } + } + } + } +} diff --git a/lexicons/app/bsky/unspecced/getSuggestedUsersForExplore.json b/lexicons/app/bsky/unspecced/getSuggestedUsersForExplore.json new file mode 100644 index 0000000000..a37a21a7eb --- /dev/null +++ b/lexicons/app/bsky/unspecced/getSuggestedUsersForExplore.json @@ -0,0 +1,45 @@ +{ + "lexicon": 1, + "id": "app.bsky.unspecced.getSuggestedUsersForExplore", + "defs": { + "main": { + "type": "query", + "description": "Get a list of suggested users for the Explore page", + "parameters": { + "type": "params", + "properties": { + "category": { + "type": "string", + "description": "Category of users to get suggestions for." + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 50, + "default": 25 + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["actors"], + "properties": { + "actors": { + "type": "array", + "items": { + "type": "ref", + "ref": "app.bsky.actor.defs#profileView" + } + }, + "recIdStr": { + "type": "string", + "description": "Snowflake for this recommendation, use when submitting recommendation events." + } + } + } + } + } + } +} diff --git a/lexicons/app/bsky/unspecced/getSuggestedUsersForExploreSkeleton.json b/lexicons/app/bsky/unspecced/getSuggestedUsersForExploreSkeleton.json new file mode 100644 index 0000000000..b3f3186e84 --- /dev/null +++ b/lexicons/app/bsky/unspecced/getSuggestedUsersForExploreSkeleton.json @@ -0,0 +1,50 @@ +{ + "lexicon": 1, + "id": "app.bsky.unspecced.getSuggestedUsersForExploreSkeleton", + "defs": { + "main": { + "type": "query", + "description": "Get a skeleton of suggested users for the Explore page. Intended to be called and hydrated by app.bsky.unspecced.getSuggestedUsersForExplore", + "parameters": { + "type": "params", + "properties": { + "viewer": { + "type": "string", + "format": "did", + "description": "DID of the account making the request (not included for public/unauthenticated queries)." + }, + "category": { + "type": "string", + "description": "Category of users to get suggestions for." + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 50, + "default": 25 + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["dids"], + "properties": { + "dids": { + "type": "array", + "items": { + "type": "string", + "format": "did" + } + }, + "recIdStr": { + "type": "string", + "description": "Snowflake for this recommendation, use when submitting recommendation events." + } + } + } + } + } + } +} diff --git a/lexicons/app/bsky/unspecced/getSuggestedUsersForSeeMore.json b/lexicons/app/bsky/unspecced/getSuggestedUsersForSeeMore.json new file mode 100644 index 0000000000..1938df7e55 --- /dev/null +++ b/lexicons/app/bsky/unspecced/getSuggestedUsersForSeeMore.json @@ -0,0 +1,45 @@ +{ + "lexicon": 1, + "id": "app.bsky.unspecced.getSuggestedUsersForSeeMore", + "defs": { + "main": { + "type": "query", + "description": "Get a list of suggested users for the See More page", + "parameters": { + "type": "params", + "properties": { + "category": { + "type": "string", + "description": "Category of users to get suggestions for." + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 50, + "default": 25 + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["actors"], + "properties": { + "actors": { + "type": "array", + "items": { + "type": "ref", + "ref": "app.bsky.actor.defs#profileView" + } + }, + "recIdStr": { + "type": "string", + "description": "Snowflake for this recommendation, use when submitting recommendation events." + } + } + } + } + } + } +} diff --git a/lexicons/app/bsky/unspecced/getSuggestedUsersForSeeMoreSkeleton.json b/lexicons/app/bsky/unspecced/getSuggestedUsersForSeeMoreSkeleton.json new file mode 100644 index 0000000000..954b518d77 --- /dev/null +++ b/lexicons/app/bsky/unspecced/getSuggestedUsersForSeeMoreSkeleton.json @@ -0,0 +1,50 @@ +{ + "lexicon": 1, + "id": "app.bsky.unspecced.getSuggestedUsersForSeeMoreSkeleton", + "defs": { + "main": { + "type": "query", + "description": "Get a skeleton of suggested users for the See More page. Intended to be called and hydrated by app.bsky.unspecced.getSuggestedUsersForSeeMore", + "parameters": { + "type": "params", + "properties": { + "viewer": { + "type": "string", + "format": "did", + "description": "DID of the account making the request (not included for public/unauthenticated queries)." + }, + "category": { + "type": "string", + "description": "Category of users to get suggestions for." + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 50, + "default": 25 + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["dids"], + "properties": { + "dids": { + "type": "array", + "items": { + "type": "string", + "format": "did" + } + }, + "recIdStr": { + "type": "string", + "description": "Snowflake for this recommendation, use when submitting recommendation events." + } + } + } + } + } + } +} diff --git a/lexicons/com/atproto/temp/checkHandleAvailability.json b/lexicons/com/atproto/temp/checkHandleAvailability.json new file mode 100644 index 0000000000..ffbdd6f732 --- /dev/null +++ b/lexicons/com/atproto/temp/checkHandleAvailability.json @@ -0,0 +1,88 @@ +{ + "lexicon": 1, + "id": "com.atproto.temp.checkHandleAvailability", + "defs": { + "main": { + "type": "query", + "description": "Checks whether the provided handle is available. If the handle is not available, available suggestions will be returned. Optional inputs will be used to generate suggestions.", + "parameters": { + "type": "params", + "required": ["handle"], + "properties": { + "handle": { + "type": "string", + "format": "handle", + "description": "Tentative handle. Will be checked for availability or used to build handle suggestions." + }, + "email": { + "type": "string", + "description": "User-provided email. Might be used to build handle suggestions." + }, + "birthDate": { + "type": "string", + "format": "datetime", + "description": "User-provided birth date. Might be used to build handle suggestions." + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["handle", "result"], + "properties": { + "handle": { + "type": "string", + "format": "handle", + "description": "Echo of the input handle." + }, + "result": { + "type": "union", + "refs": ["#resultAvailable", "#resultUnavailable"] + } + } + } + }, + "errors": [ + { + "name": "InvalidEmail", + "description": "An invalid email was provided." + } + ] + }, + "resultAvailable": { + "type": "object", + "description": "Indicates the provided handle is available.", + "properties": {} + }, + "resultUnavailable": { + "type": "object", + "description": "Indicates the provided handle is unavailable and gives suggestions of available handles.", + "required": ["suggestions"], + "properties": { + "suggestions": { + "type": "array", + "description": "List of suggested handles based on the provided inputs.", + "items": { + "type": "ref", + "ref": "#suggestion" + } + } + } + }, + "suggestion": { + "type": "object", + "required": ["handle", "method"], + "properties": { + "handle": { + "type": "string", + "format": "handle" + }, + "method": { + "type": "string", + "description": "Method used to build this suggestion. Should be considered opaque to clients. Can be used for metrics." + } + } + } + } +} diff --git a/lexicons/com/atproto/temp/checkSignupQueue.json b/lexicons/com/atproto/temp/checkSignupQueue.json new file mode 100644 index 0000000000..b7d9e65d7c --- /dev/null +++ b/lexicons/com/atproto/temp/checkSignupQueue.json @@ -0,0 +1,22 @@ +{ + "lexicon": 1, + "id": "com.atproto.temp.checkSignupQueue", + "defs": { + "main": { + "type": "query", + "description": "Check accounts location in signup queue.", + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["activated"], + "properties": { + "activated": { "type": "boolean" }, + "placeInQueue": { "type": "integer" }, + "estimatedTimeMs": { "type": "integer" } + } + } + } + } + } +} diff --git a/src/components/Autocomplete/useAutocomplete/index.ts b/src/components/Autocomplete/useAutocomplete/index.ts index ad14ae54bc..86dc9e7cd1 100644 --- a/src/components/Autocomplete/useAutocomplete/index.ts +++ b/src/components/Autocomplete/useAutocomplete/index.ts @@ -62,7 +62,6 @@ export function useAutocomplete({ key: profile.did, type: 'profile' as const, value: '@' + profile.handle, - // TODO(phase4): drop toLex once searchActorsTypeahead (bridge agent) // emits #/lexicons views profile: toLex(profile), })) @@ -134,10 +133,7 @@ function moderateProfileItem({ item: AutocompleteProfile moderationOpts: ModerationOpts }) { - // TODO(phase4): drop toLex once searchActorsTypeahead emits #/lexicons views - const modui = moderateProfile(toLex(item.profile), moderationOpts).ui( - 'profileList', - ) + const modui = moderateProfile(item.profile, moderationOpts).ui('profileList') const isExactMatch = query && item.profile.handle.toLowerCase() === query if ( diff --git a/src/components/AvatarBubbles.tsx b/src/components/AvatarBubbles.tsx index 7cbfe1025f..6189141934 100644 --- a/src/components/AvatarBubbles.tsx +++ b/src/components/AvatarBubbles.tsx @@ -17,7 +17,6 @@ import {UserAvatar} from '#/view/com/util/UserAvatar' import {atoms as a, useTheme} from '#/alf' import {Person_Filled_Corner2_Rounded as PersonIcon} from '#/components/icons/Person' import type * as bsky from '#/types/bsky' -import {toLex} from '#/types/bsky' type Layout = { size: number @@ -163,10 +162,7 @@ function AvatarBubble({ type="user" hideLiveBadge noBorder - // TODO(phase4): drop toLex once profile props emit #/lexicons views - moderation={moderateProfile(toLex(profile), moderationOpts).ui( - 'avatar', - )} + moderation={moderateProfile(profile, moderationOpts).ui('avatar')} /> ) : ( diff --git a/src/components/AvatarStack.tsx b/src/components/AvatarStack.tsx index c24f058c70..dc7a8395c3 100644 --- a/src/components/AvatarStack.tsx +++ b/src/components/AvatarStack.tsx @@ -7,7 +7,6 @@ import {useProfilesQuery} from '#/state/queries/profile' import {UserAvatar} from '#/view/com/util/UserAvatar' import {atoms as a, useTheme} from '#/alf' import type * as bsky from '#/types/bsky' -import {toLex} from '#/types/bsky' export function AvatarStack({ profiles, @@ -35,8 +34,7 @@ export function AvatarStack({ : profiles.map(item => ({ key: item.did, profile: item, - // TODO(phase4): drop toLex once useProfilesQuery emits #/lexicons views - moderation: moderateProfile(toLex(item), moderationOpts), + moderation: moderateProfile(item, moderationOpts), })) return ( diff --git a/src/components/KnownFollowers.tsx b/src/components/KnownFollowers.tsx index 96e01eb767..b6f90fc401 100644 --- a/src/components/KnownFollowers.tsx +++ b/src/components/KnownFollowers.tsx @@ -11,7 +11,6 @@ import {Link, type LinkProps} from '#/components/Link' import {Text} from '#/components/Typography' import {type app} from '#/lexicons' import type * as bsky from '#/types/bsky' -import {toLex} from '#/types/bsky' const AVI_SIZE = 30 const AVI_SIZE_SMALL = 20 @@ -96,8 +95,7 @@ function KnownFollowersInner({ const textStyle = [a.text_sm, a.leading_snug, t.atoms.text_contrast_medium] const slice = cachedKnownFollowers.followers.slice(0, 3).map(f => { - // TODO(phase4): drop toLex once KnownFollowers emits #/lexicons views - const moderation = moderateProfile(toLex(f), moderationOpts) + const moderation = moderateProfile(f, moderationOpts) return { profile: { ...f, diff --git a/src/components/ListCard.tsx b/src/components/ListCard.tsx index 028e0dfe86..d9e15f9108 100644 --- a/src/components/ListCard.tsx +++ b/src/components/ListCard.tsx @@ -24,7 +24,6 @@ import * as Hider from '#/components/moderation/Hider' import {Text} from '#/components/Typography' import {type app} from '#/lexicons' import type * as bsky from '#/types/bsky' -import {toLex} from '#/types/bsky' /* * This component is based on `FeedCard` and is tightly coupled with that @@ -55,8 +54,7 @@ export function Default( const {view, showPinButton} = props const moderationOpts = useModerationOpts() const moderation = moderationOpts - ? // TODO(phase4): drop toLex once ListView props emit #/lexicons views - moderateUserList(toLex(view), moderationOpts) + ? moderateUserList(view, moderationOpts) : undefined return ( diff --git a/src/components/NewskieDialog.tsx b/src/components/NewskieDialog.tsx index 5b346d051a..43025aca94 100644 --- a/src/components/NewskieDialog.tsx +++ b/src/components/NewskieDialog.tsx @@ -20,7 +20,6 @@ import * as StarterPackCard from '#/components/StarterPack/StarterPackCard' import {Text} from '#/components/Typography' import {IS_NATIVE} from '#/env' import {type app} from '#/lexicons' -import {toLex} from '#/types/bsky' export function NewskieDialog({ profile, @@ -90,8 +89,7 @@ function DialogInner({ const profileName = useMemo(() => { if (!moderationOpts) return profile.displayName || profile.handle - // TODO(phase4): drop toLex once ProfileViewDetailed prop emits #/lexicons views - const moderation = moderateProfile(toLex(profile), moderationOpts) + const moderation = moderateProfile(profile, moderationOpts) return sanitizeDisplayName( profile.displayName || profile.handle, moderation.ui('displayName'), diff --git a/src/components/Post/Embed/FeedEmbed.tsx b/src/components/Post/Embed/FeedEmbed.tsx index 56de18c6c8..9e1e3e022d 100644 --- a/src/components/Post/Embed/FeedEmbed.tsx +++ b/src/components/Post/Embed/FeedEmbed.tsx @@ -5,7 +5,6 @@ import {useModerationOpts} from '#/state/preferences/moderation-opts' import {atoms as a, useTheme} from '#/alf' import * as FeedCard from '#/components/FeedCard' import {ContentHider} from '#/components/moderation/ContentHider' -import {toLex} from '#/types/bsky' import {type EmbedType} from '#/types/bsky/post' import {type CommonProps} from './types' @@ -41,8 +40,7 @@ export function ModeratedFeedEmbed({ const moderationOpts = useModerationOpts() const moderation = useMemo(() => { return moderationOpts - ? // TODO(phase4): drop toLex once feed embed view emits #/lexicons views - moderateFeedGenerator(toLex(embed.view), moderationOpts) + ? moderateFeedGenerator(embed.view, moderationOpts) : undefined }, [embed.view, moderationOpts]) return ( diff --git a/src/components/Post/Embed/ListEmbed.tsx b/src/components/Post/Embed/ListEmbed.tsx index 4e3bb58613..11ed196597 100644 --- a/src/components/Post/Embed/ListEmbed.tsx +++ b/src/components/Post/Embed/ListEmbed.tsx @@ -5,7 +5,6 @@ import {useModerationOpts} from '#/state/preferences/moderation-opts' import {atoms as a, useTheme} from '#/alf' import * as ListCard from '#/components/ListCard' import {ContentHider} from '#/components/moderation/ContentHider' -import {toLex} from '#/types/bsky' import {type EmbedType} from '#/types/bsky/post' import {type CommonProps} from './types' @@ -31,8 +30,7 @@ export function ModeratedListEmbed({ const moderationOpts = useModerationOpts() const moderation = useMemo(() => { return moderationOpts - ? // TODO(phase4): drop toLex once list embed view emits #/lexicons views - moderateUserList(toLex(embed.view), moderationOpts) + ? moderateUserList(embed.view, moderationOpts) : undefined }, [embed.view, moderationOpts]) return ( diff --git a/src/components/Post/Embed/index.tsx b/src/components/Post/Embed/index.tsx index 33e9bf2d9b..1616bff5de 100644 --- a/src/components/Post/Embed/index.tsx +++ b/src/components/Post/Embed/index.tsx @@ -268,9 +268,7 @@ export function QuoteEmbed({ [embed], ) const moderation = useMemo(() => { - return moderationOpts - ? moderatePost(bsky.toLex(quote), moderationOpts) - : undefined + return moderationOpts ? moderatePost(quote, moderationOpts) : undefined }, [quote, moderationOpts]) const t = useTheme() diff --git a/src/components/PostControls/ShareMenu/RecentChats.tsx b/src/components/PostControls/ShareMenu/RecentChats.tsx index 5c2828a01c..33441352fc 100644 --- a/src/components/PostControls/ShareMenu/RecentChats.tsx +++ b/src/components/PostControls/ShareMenu/RecentChats.tsx @@ -22,7 +22,6 @@ import {ProfileBadges} from '#/components/ProfileBadges' import {Text} from '#/components/Typography' import {useAnalytics} from '#/analytics' import {type chat} from '#/lexicons' -import {toLex} from '#/types/bsky' export function RecentChats({ postUri, @@ -121,8 +120,7 @@ function RecentChatItem({ const primaryProfile = useProfileShadow(primaryMember) - // TODO(phase4): drop toLex once useProfileShadow emits #/lexicons views - const moderation = moderateProfile(toLex(primaryProfile), moderationOpts) + const moderation = moderateProfile(primaryProfile, moderationOpts) const name = convo.kind === 'group' ? convo.details.name diff --git a/src/components/ProfileCard.tsx b/src/components/ProfileCard.tsx index d2b18e7b1c..0ef9d35807 100644 --- a/src/components/ProfileCard.tsx +++ b/src/components/ProfileCard.tsx @@ -44,7 +44,7 @@ import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' import {type Metrics} from '#/analytics' import {useActorStatus} from '#/features/liveNow' -import * as bsky from '#/types/bsky' +import type * as bsky from '#/types/bsky' export function Default({ profile, @@ -170,7 +170,7 @@ export function Avatar({ liveOverride?: boolean size?: number }) { - const moderation = moderateProfile(bsky.toLex(profile), moderationOpts) + const moderation = moderateProfile(profile, moderationOpts) const {isActive: live} = useActorStatus(profile) @@ -240,7 +240,7 @@ function InlineNameAndHandle({ moderationOpts: ModerationOpts }) { const t = useTheme() - const moderation = moderateProfile(bsky.toLex(profile), moderationOpts) + const moderation = moderateProfile(profile, moderationOpts) const name = sanitizeDisplayName( profile.displayName || sanitizeHandle(profile.handle), moderation.ui('displayName'), @@ -294,7 +294,7 @@ export function Name({ style?: StyleProp textStyle?: StyleProp }) { - const moderation = moderateProfile(bsky.toLex(profile), moderationOpts) + const moderation = moderateProfile(profile, moderationOpts) const name = sanitizeDisplayName( profile.displayName || sanitizeHandle(profile.handle), moderation.ui('displayName'), @@ -479,7 +479,7 @@ export function FollowButtonInner({ }: FollowButtonProps) { const {t: l} = useLingui() const profile = useProfileShadow(profileUnshadowed) - const moderation = moderateProfile(bsky.toLex(profile), moderationOpts) + const moderation = moderateProfile(profile, moderationOpts) const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue( profile, logContext, @@ -617,7 +617,7 @@ export function Labels({ profile: bsky.profile.AnyProfileView moderationOpts: ModerationOpts }) { - const moderation = moderateProfile(bsky.toLex(profile), moderationOpts) + const moderation = moderateProfile(profile, moderationOpts) const modui = moderation.ui('profileList') const followedBy = profile.viewer?.followedBy diff --git a/src/components/ProfileHoverCard/index.web.tsx b/src/components/ProfileHoverCard/index.web.tsx index 6d60774f78..4f05f8e7ae 100644 --- a/src/components/ProfileHoverCard/index.web.tsx +++ b/src/components/ProfileHoverCard/index.web.tsx @@ -39,7 +39,6 @@ import {IS_WEB_TOUCH_DEVICE} from '#/env' import {useActorStatus} from '#/features/liveNow' import {LiveStatus} from '#/features/liveNow/components/LiveStatusDialog' import {type app} from '#/lexicons' -import {toLex} from '#/types/bsky' import {type ProfileHoverCardProps} from './types' const floatingMiddlewares = [ @@ -424,8 +423,7 @@ function Inner({ const {_, i18n} = useLingui() const {currentAccount} = useSession() const moderation = useMemo( - // TODO(phase4): drop toLex once ProfileViewDetailed prop emits #/lexicons views - () => moderateProfile(toLex(profile), moderationOpts), + () => moderateProfile(profile, moderationOpts), [profile, moderationOpts], ) const [descriptionRT] = useRichText(profile.description ?? '') diff --git a/src/components/StarterPack/Wizard/WizardListCard.tsx b/src/components/StarterPack/Wizard/WizardListCard.tsx index 7ade0e79f9..1d33b27e40 100644 --- a/src/components/StarterPack/Wizard/WizardListCard.tsx +++ b/src/components/StarterPack/Wizard/WizardListCard.tsx @@ -26,7 +26,6 @@ import {Text} from '#/components/Typography' import {useAnalytics} from '#/analytics' import {type app} from '#/lexicons' import type * as bsky from '#/types/bsky' -import {toLex} from '#/types/bsky' function WizardListCard({ type, @@ -140,10 +139,7 @@ export function WizardProfileCard({ const included = isTarget || state.profiles.some(p => p.did === profile.did) const disabled = isTarget || (!included && state.profiles.length >= STARTER_PACK_MAX_SIZE) - // TODO(phase4): drop toLex once profile prop emits #/lexicons views - const moderationUi = moderateProfile(toLex(profile), moderationOpts).ui( - 'avatar', - ) + const moderationUi = moderateProfile(profile, moderationOpts).ui('avatar') const displayName = profile.displayName ? sanitizeDisplayName(profile.displayName) : `@${sanitizeHandle(profile.handle)}` @@ -194,11 +190,9 @@ export function WizardFeedCard({ const isDiscover = generator.uri === DISCOVER_FEED_URI const included = isDiscover || state.feeds.some(f => f.uri === generator.uri) const disabled = isDiscover || (!included && state.feeds.length >= 3) - // TODO(phase4): drop toLex once GeneratorView prop emits #/lexicons views - const moderationUi = moderateFeedGenerator( - toLex(generator), - moderationOpts, - ).ui('avatar') + const moderationUi = moderateFeedGenerator(generator, moderationOpts).ui( + 'avatar', + ) const onPress = () => { if (disabled) return diff --git a/src/components/dialogs/SearchablePeopleList.tsx b/src/components/dialogs/SearchablePeopleList.tsx index ed509d9d6c..3813a3c745 100644 --- a/src/components/dialogs/SearchablePeopleList.tsx +++ b/src/components/dialogs/SearchablePeopleList.tsx @@ -33,7 +33,6 @@ import * as ProfileCard from '#/components/ProfileCard' import {Text} from '#/components/Typography' import {IS_WEB} from '#/env' import type * as bsky from '#/types/bsky' -import {toLex} from '#/types/bsky' import {AvatarBubbles} from '../AvatarBubbles' import {Error} from '../Error' import {ProfileBadges} from '../ProfileBadges' @@ -411,8 +410,7 @@ function DefaultProfileCard({ const t = useTheme() const {t: l} = useLingui() const enabled = canBeMessaged(profile) - // TODO(phase4): drop toLex once profile prop emits #/lexicons views - const moderation = moderateProfile(toLex(profile), moderationOpts) + const moderation = moderateProfile(profile, moderationOpts) const handle = sanitizeHandle(profile.handle, '@') const displayName = createSanitizedDisplayName( profile, @@ -488,8 +486,7 @@ function ExistingChatCard({ : createSanitizedDisplayName( convo.primaryMember, true, - // TODO(phase4): drop toLex once convo primaryMember emits #/lexicons views - moderateProfile(toLex(convo.primaryMember), moderationOpts).ui( + moderateProfile(convo.primaryMember, moderationOpts).ui( 'displayName', ), ) diff --git a/src/components/dialogs/lists/CreateOrEditListDialog.tsx b/src/components/dialogs/lists/CreateOrEditListDialog.tsx index f3d0b74a65..19272906c3 100644 --- a/src/components/dialogs/lists/CreateOrEditListDialog.tsx +++ b/src/components/dialogs/lists/CreateOrEditListDialog.tsx @@ -28,7 +28,6 @@ import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' import {IS_WEB} from '#/env' import {type app} from '#/lexicons' -import {toLex} from '#/types/bsky' const DISPLAY_NAME_MAX_GRAPHEMES = 64 const DESCRIPTION_MAX_GRAPHEMES = 300 @@ -165,9 +164,8 @@ function DialogInner({ // We want to be working with a blank state here, so let's get the // serialized version and turn it back into a RichText - // TODO(phase4): drop toLex once the list view producer emits #/lexicons facets const serialized = richTextToString( - new RichTextAPI({text, facets: toLex(facets)}), + new RichTextAPI({text, facets: facets}), false, ) diff --git a/src/components/dms/ChatProfileTabs.tsx b/src/components/dms/ChatProfileTabs.tsx index 1e6e88217e..5a0e7a8fb3 100644 --- a/src/components/dms/ChatProfileTabs.tsx +++ b/src/components/dms/ChatProfileTabs.tsx @@ -15,7 +15,6 @@ import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Ti import * as ProfileCard from '#/components/ProfileCard' import {Text} from '#/components/Typography' import type * as bsky from '#/types/bsky' -import {toLex} from '#/types/bsky' type Props = { testID?: string @@ -90,8 +89,7 @@ function Tab({ const {t: l} = useLingui() const moderationOpts = useModerationOpts() - // TODO(phase4): drop toLex once profile prop emits #/lexicons views - const moderation = moderateProfile(toLex(profile), moderationOpts!) + const moderation = moderateProfile(profile, moderationOpts!) const displayName = sanitizeDisplayName( profile.displayName || sanitizeHandle(profile.handle), moderation.ui('displayName'), diff --git a/src/components/dms/InitiateChatFlow.tsx b/src/components/dms/InitiateChatFlow.tsx index 95dd6045c9..271016a5d5 100644 --- a/src/components/dms/InitiateChatFlow.tsx +++ b/src/components/dms/InitiateChatFlow.tsx @@ -54,7 +54,6 @@ import {Text} from '#/components/Typography' import {useAgeAssurance} from '#/ageAssurance' import {IS_NATIVE, IS_WEB} from '#/env' import type * as bsky from '#/types/bsky' -import {toLex} from '#/types/bsky' type NewGroupChatItem = { type: 'newGroupChat' @@ -1071,8 +1070,7 @@ function DefaultProfileCard({ const t = useTheme() const {t: l} = useLingui() const enabled = canBeMessaged(profile) - // TODO(phase4): drop toLex once profile prop emits #/lexicons views - const moderation = moderateProfile(toLex(profile), moderationOpts) + const moderation = moderateProfile(profile, moderationOpts) const handle = sanitizeHandle(profile.handle, '@') const displayName = sanitizeDisplayName( profile.displayName || sanitizeHandle(profile.handle), diff --git a/src/components/dms/MessageContextMenu.tsx b/src/components/dms/MessageContextMenu.tsx index 5abce35fb9..1807f2888d 100644 --- a/src/components/dms/MessageContextMenu.tsx +++ b/src/components/dms/MessageContextMenu.tsx @@ -29,7 +29,6 @@ import {useAnalytics} from '#/analytics' import {IS_NATIVE} from '#/env' import {type chat} from '#/lexicons' import type * as bsky from '#/types/bsky' -import {toLex} from '#/types/bsky' import {EmojiReactionPicker} from './EmojiReactionPicker' import {canReact, hasReachedReactionLimit} from './util' @@ -87,8 +86,7 @@ export let MessageContextMenu = ({ const str = richTextToString( new RichText({ text: message.text, - // TODO(phase4): drop toLex once the message producer emits #/lexicons facets - facets: toLex(message.facets), + facets: message.facets, }), true, ) diff --git a/src/components/dms/MessageItem.tsx b/src/components/dms/MessageItem.tsx index 590f8f6dde..7646da471b 100644 --- a/src/components/dms/MessageItem.tsx +++ b/src/components/dms/MessageItem.tsx @@ -344,9 +344,7 @@ let MessageItem = ({ size={AVATAR_SIZE} type={profile.associated?.labeler ? 'labeler' : 'user'} onBeforePress={() => unstableCacheProfileView(queryClient, profile)} - moderation={moderateProfile(bsky.toLex(profile), moderationOpts).ui( - 'avatar', - )} + moderation={moderateProfile(profile, moderationOpts).ui('avatar')} /> ) : ( diff --git a/src/components/dms/MessagesListHeader.tsx b/src/components/dms/MessagesListHeader.tsx index c35fbc13da..adf8e3b1f5 100644 --- a/src/components/dms/MessagesListHeader.tsx +++ b/src/components/dms/MessagesListHeader.tsx @@ -21,7 +21,6 @@ import {Link} from '#/components/Link' import {ProfileBadges} from '#/components/ProfileBadges' import {Text} from '#/components/Typography' import {IS_LIQUID_GLASS} from '#/env' -import {toLex} from '#/types/bsky' import {type ConvoWithDetails} from './util' const PFP_SIZE = 40 @@ -86,8 +85,7 @@ function ProfileHeaderReady({ const {t: l} = useLingui() const profile = useProfileShadow(convo.primaryMember) - // TODO(phase4): drop toLex once useProfileShadow emits #/lexicons views - const moderation = moderateProfile(toLex(profile), moderationOpts) + const moderation = moderateProfile(profile, moderationOpts) const blockInfo = useMemo(() => { const modui = moderation.ui('profileView') diff --git a/src/components/dms/components/GroupChatProfileCard.tsx b/src/components/dms/components/GroupChatProfileCard.tsx index fc7823f834..90d15c4b5f 100644 --- a/src/components/dms/components/GroupChatProfileCard.tsx +++ b/src/components/dms/components/GroupChatProfileCard.tsx @@ -10,7 +10,6 @@ import * as Toggle from '#/components/forms/Toggle' import * as ProfileCard from '#/components/ProfileCard' import {Text} from '#/components/Typography' import type * as bsky from '#/types/bsky' -import {toLex} from '#/types/bsky' export function GroupChatProfileCard({ profile, @@ -21,8 +20,7 @@ export function GroupChatProfileCard({ }) { const t = useTheme() const enabled = canBeAddedToGroup(profile) - // TODO(phase4): drop toLex once profile prop emits #/lexicons views - const moderation = moderateProfile(toLex(profile), moderationOpts) + const moderation = moderateProfile(profile, moderationOpts) const handle = sanitizeHandle(profile.handle, '@') const displayName = sanitizeDisplayName( profile.displayName || sanitizeHandle(profile.handle), diff --git a/src/components/dms/util.ts b/src/components/dms/util.ts index 8b68270bd6..135fb0dfaf 100644 --- a/src/components/dms/util.ts +++ b/src/components/dms/util.ts @@ -154,10 +154,7 @@ export function canReact({ } if (primaryMember && moderationOpts) { - const moderation = moderateProfile( - bsky.toLex(primaryMember), - moderationOpts, - ) + const moderation = moderateProfile(primaryMember, moderationOpts) if (convoState.convo.kind === 'direct') { // Either direction (blocking or blocked-by) hides reactions in 1-1s if (moderation.blocked) return false diff --git a/src/components/intents/GroupChatJoinDialog.tsx b/src/components/intents/GroupChatJoinDialog.tsx index bc928f09f4..249d787dd4 100644 --- a/src/components/intents/GroupChatJoinDialog.tsx +++ b/src/components/intents/GroupChatJoinDialog.tsx @@ -395,11 +395,9 @@ function GroupChatJoinDialogContent({code}: {code?: string}) { {createSanitizedDisplayName( joinLinkPreview.owner, true, - // TODO(phase4): drop toLex once join link preview emits #/lexicons views - moderateProfile( - bsky.toLex(joinLinkPreview.owner), - moderationOpts, - ).ui('displayName'), + moderateProfile(joinLinkPreview.owner, moderationOpts).ui( + 'displayName', + ), )} diff --git a/src/components/moderation/PostAlerts.tsx b/src/components/moderation/PostAlerts.tsx index cd9e841f5f..95f4c0e56e 100644 --- a/src/components/moderation/PostAlerts.tsx +++ b/src/components/moderation/PostAlerts.tsx @@ -16,7 +16,6 @@ import { } from '#/components/moderation/LabelsOnMeDialog' import * as Pills from '#/components/Pills' import {type app, type com} from '#/lexicons' -import {toLex} from '#/types/bsky' export function PostAlerts({ post, @@ -68,8 +67,7 @@ export function PostAlerts({ */ const shownCauses = [...alerts, ...informs, ...modui.blurs] const additionalLabels = filterUserFacingLabels( - // TODO(phase4): drop toLex once PostView labels are #/lexicons-typed - toLex(allLabels), + allLabels, currentAccount?.did, ).filter(label => shownCauses.every( diff --git a/src/components/moderation/ReportDialog/utils/parseReportSubject.ts b/src/components/moderation/ReportDialog/utils/parseReportSubject.ts index f2243f322d..f017b6456c 100644 --- a/src/components/moderation/ReportDialog/utils/parseReportSubject.ts +++ b/src/components/moderation/ReportDialog/utils/parseReportSubject.ts @@ -24,21 +24,7 @@ export function parseReportSubject( } } - /* - * TODO(phase4): drop toLex once ReportSubject is a #/lexicons union. The view - * subjects are structurally the #/lexicons shapes; we bridge here so the - * `isType` schema guards below narrow against the lexicon `$type`s. - */ - const subject = bsky.toLex< - | app.bsky.actor.defs.ProfileViewBasic - | app.bsky.actor.defs.ProfileView - | app.bsky.actor.defs.ProfileViewDetailed - | app.bsky.actor.defs.StatusView - | app.bsky.graph.defs.ListView - | app.bsky.feed.defs.GeneratorView - | app.bsky.graph.defs.StarterPackView - | app.bsky.feed.defs.PostView - >(rawSubject) + const subject = rawSubject if ( bsky.isType(app.bsky.actor.defs.profileViewBasic, subject) || diff --git a/src/features/liveNow/components/GoLiveDisabledDialog.tsx b/src/features/liveNow/components/GoLiveDisabledDialog.tsx index e3290d6ba5..fefcf6dc72 100644 --- a/src/features/liveNow/components/GoLiveDisabledDialog.tsx +++ b/src/features/liveNow/components/GoLiveDisabledDialog.tsx @@ -15,7 +15,6 @@ import {Loader} from '#/components/Loader' import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' import {type app, com, tools} from '#/lexicons' -import {toLex} from '#/types/bsky' export function GoLiveDisabledDialog({ control, @@ -60,7 +59,7 @@ export function DialogInner({ } else { await pdsClient.call( com.atproto.moderation.createReport, - toLex({ + { reasonType: tools.ozone.report.defs.reasonAppeal.value, subject: { $type: 'com.atproto.repo.strongRef', @@ -68,7 +67,7 @@ export function DialogInner({ cid: status.cid, }, reason: details, - }), + }, { service: api.moderation.service, }, diff --git a/src/features/liveNow/components/LiveStatusDialog.tsx b/src/features/liveNow/components/LiveStatusDialog.tsx index 5bf090516f..242c08378a 100644 --- a/src/features/liveNow/components/LiveStatusDialog.tsx +++ b/src/features/liveNow/components/LiveStatusDialog.tsx @@ -27,7 +27,7 @@ import {Text} from '#/components/Typography' import {useAnalytics} from '#/analytics' import {LiveIndicator} from '#/features/liveNow/components/LiveIndicator' import {type app} from '#/lexicons' -import * as bsky from '#/types/bsky' +import type * as bsky from '#/types/bsky' export function LiveStatusDialog({ control, @@ -115,8 +115,7 @@ export function LiveStatus({ const dialogContext = Dialog.useDialogContext() const moderation = useMemo(() => { if (!moderationOpts) return undefined - // TODO(phase4): drop toLex once profile producers emit #/lexicons views - return moderateStatus(bsky.toLex(profile), moderationOpts) + return moderateStatus(profile, moderationOpts) }, [profile, moderationOpts]) return ( diff --git a/src/features/liveNow/index.tsx b/src/features/liveNow/index.tsx index 24aeecc309..449f486340 100644 --- a/src/features/liveNow/index.tsx +++ b/src/features/liveNow/index.tsx @@ -23,7 +23,7 @@ import { useMaybeProfileShadow, } from '#/state/cache/profile-shadow' import {useModerationOpts} from '#/state/preferences/moderation-opts' -import {useAgent, usePdsClient, useSession} from '#/state/session' +import {usePdsClient, useSession} from '#/state/session' import {useTickEveryMinute} from '#/state/shell' import {useDialogContext} from '#/components/Dialog' import * as Toast from '#/components/Toast' @@ -105,8 +105,7 @@ export function useActorStatus(actor?: bsky.profile.AnyProfileView) { const moderation = useMemo(() => { if (!actor || !('status' in actor && actor.status)) return undefined if (!moderationOpts) return undefined - // TODO(phase4): drop toLex once profile producers emit #/lexicons views - return moderateStatus(bsky.toLex(actor), moderationOpts) + return moderateStatus(actor, moderationOpts) }, [actor, moderationOpts]) return useMemo(() => { @@ -120,12 +119,7 @@ export function useActorStatus(actor?: bsky.profile.AnyProfileView) { } if (shadowed && 'status' in shadowed && shadowed.status) { - /* - * TODO(phase4): drop toLex once profile-shadow emits #/lexicons views. - * The shadow store still holds old `@atproto/api` StatusViews, so brand - * it once here to feed the new-world validation and returned view. - */ - const status = bsky.toLex(shadowed.status) + const status = shadowed.status const isValid = isStatusValidForViewers(status, config) const isDisabled = status.isDisabled || false const isActive = isStatusStillActive(status.expiresAt) @@ -195,7 +189,6 @@ export function useLiveLinkMetaQuery(url: string | null) { const liveNowConfig = useLiveNowConfig() const {_} = useLingui() - const agent = useAgent() return useQuery({ enabled: !!url, queryKey: ['link-meta', url], @@ -213,7 +206,7 @@ export function useLiveLinkMetaQuery(url: string | null) { ) } - return await getLinkMeta(agent, url) + return await getLinkMeta(url) }, }) } diff --git a/src/lib/api/feed/demo.ts b/src/lib/api/feed/demo.ts index 72878917d5..d4a480aea1 100644 --- a/src/lib/api/feed/demo.ts +++ b/src/lib/api/feed/demo.ts @@ -2,7 +2,6 @@ import {type Client} from '@atproto/lex-client' import {DEMO_FEED} from '#/lib/demo' import {type app} from '#/lexicons' -import {toLex} from '#/types/bsky' import {type FeedAPI, type FeedAPIResponse} from './types' export class DemoFeedAPI implements FeedAPI { @@ -12,17 +11,13 @@ export class DemoFeedAPI implements FeedAPI { this.client = client } + // eslint-disable-next-line @typescript-eslint/require-await async peekLatest(): Promise { - /* - * TODO(phase4): drop this cast once `#/lib/demo` (DEMO_FEED) sources its - * feed items from `#/lexicons`. Its records are still typed against the old - * `@atproto/api` FeedViewPost, which does not assign to the branded lexicon - * type this method must return. - */ - return toLex(DEMO_FEED.feed[0]) + return DEMO_FEED.feed[0] } + // eslint-disable-next-line @typescript-eslint/require-await async fetch(): Promise { - return toLex(DEMO_FEED) + return DEMO_FEED } } diff --git a/src/lib/api/feed/merge.ts b/src/lib/api/feed/merge.ts index 49fbba0ae0..789c060afc 100644 --- a/src/lib/api/feed/merge.ts +++ b/src/lib/api/feed/merge.ts @@ -8,7 +8,6 @@ import {feedUriToHref} from '#/lib/strings/url-helpers' import {getContentLanguages} from '#/state/preferences/languages' import {type FeedParams} from '#/state/queries/post-feed' import {app} from '#/lexicons' -import {toLex} from '#/types/bsky' import {FeedTuner} from '../feed-manip' import {type FeedTunerFn} from '../feed-manip' import { @@ -264,13 +263,7 @@ class MergeFeedSource_Following extends MergeFeedSource { return { success: true, cursor: res.cursor, - /* - * TODO(phase4): drop the toLex once `#/lib/api/feed-manip` (FeedTuner) - * flips its FeedViewPost source from `@atproto/api` to `#/lexicons`. Its - * `_feedPost` is still the old-world view type, which does not assign to - * the branded lexicon type this page carries. - */ - feed: slices.map(slice => toLex(slice._feedPost)), + feed: slices.map(slice => slice._feedPost), } } } diff --git a/src/lib/api/index.ts b/src/lib/api/index.ts index 6999e3938e..1e50b1c635 100644 --- a/src/lib/api/index.ts +++ b/src/lib/api/index.ts @@ -91,16 +91,7 @@ export async function post( for (let i = 0; i < thread.posts.length; i++) { const draft = thread.posts[i] - /* - * Not awaited to avoid waterfalls. `draft.richtext` is still an - * `@atproto/api` RichText (composer state is migrated by Task 7); the SDK - * RichText is structurally the same transplant, so bridge it here. - * TODO(phase4): drop toLex once composer state migrates to SDK RichText. - */ - const rtPromise = resolveRT( - resolveClients.appview, - bsky.toLex(draft.richtext), - ) + const rtPromise = resolveRT(resolveClients.appview, draft.richtext) const embedPromise = resolveEmbed( clients, queryClient, @@ -138,17 +129,11 @@ export async function post( langs, labels, } - /* - * `value` is typed `LexMap` (a loose index-signature map). A generated - * record type is a valid LexMap at runtime but a strict interface is not - * assignable to an index-signature type, so widen with `toLex` at this - * boundary. Not a brand cast - the record is already fully typed. - */ writes.push({ $type: 'com.atproto.repo.applyWrites#create', collection: 'app.bsky.feed.post', rkey: rkey, - value: bsky.toLex(record), + value: record, }) if (i === 0 && thread.threadgate.some(tg => tg.type !== 'everybody')) { @@ -156,14 +141,10 @@ export async function post( $type: 'com.atproto.repo.applyWrites#create', collection: 'app.bsky.feed.threadgate', rkey: rkey, - value: bsky.toLex( - createThreadgateRecord({ - post: uri, - allow: threadgateAllowUISettingToAllowRecordValue( - thread.threadgate, - ), - }), - ), + value: createThreadgateRecord({ + post: uri, + allow: threadgateAllowUISettingToAllowRecordValue(thread.threadgate), + }), }) } @@ -175,12 +156,12 @@ export async function post( $type: 'com.atproto.repo.applyWrites#create', collection: 'app.bsky.feed.postgate', rkey: rkey, - value: bsky.toLex({ + value: { ...thread.postgate, $type: 'app.bsky.feed.postgate', createdAt: now.toISOString(), post: uri, - }), + }, }) } @@ -426,7 +407,7 @@ async function resolveMedia( * structural shape matches the lexicon blob field; the CID hasher handles * both class instances and plain lex blobs (see computeCid). */ - video: bsky.toLex(videoDraft.pendingPublish.blobRef), + video: videoDraft.pendingPublish.blobRef, alt: videoDraft.altText || undefined, captions: captions.length === 0 ? undefined : captions, aspectRatio, @@ -475,13 +456,7 @@ async function resolveMedia( title: resolvedLink.title, description: resolvedLink.description, thumb: blob, - /* - * associatedRefs comes from getLinkMeta, still typed with the old - * `@atproto/api` StrongRef (link-meta.ts is out of scope). The shape - * is identical; bridge with toLex. - * TODO(phase4): drop toLex once link-meta migrates. - */ - associatedRefs: bsky.toLex(resolvedLink.associatedRefs), + associatedRefs: resolvedLink.associatedRefs, }, } } diff --git a/src/lib/api/resolve.ts b/src/lib/api/resolve.ts index d3c0ce2a50..36558609b4 100644 --- a/src/lib/api/resolve.ts +++ b/src/lib/api/resolve.ts @@ -23,7 +23,6 @@ import { import {type ComposerImage} from '#/state/gallery' import {createComposerImage} from '#/state/gallery' import {type ChatInvitePreview} from '#/state/queries/join-links' -import {type SessionAgent} from '#/state/session' import {type Gif} from '#/features/gifPicker/types' import {app, chat, com} from '#/lexicons' import {createGIFDescription} from '../gif-alt-text' @@ -31,13 +30,10 @@ import {createGIFDescription} from '../gif-alt-text' /** * Clients the link resolver needs. `appview` serves the `app.bsky.*` feed/graph * reads plus handle resolution; `chat` serves the group join-link previews. - * `agent` is still threaded through to {@link getLinkMeta}, which has not yet - * migrated off the bridge - it only reads the (unused) service URL from it. */ export type ResolveClients = { appview: Client chat: Client - agent: SessionAgent } type ResolvedExternalLink = { @@ -195,7 +191,7 @@ export async function resolveLink( view: res.starterPack, } } - return resolveExternal(clients, uri) + return resolveExternal(uri) // Forked from useGetPost. TODO: move into RQ. async function getPost({uri}: {uri: string}) { @@ -267,16 +263,8 @@ function getFileSlug(url: string | undefined): string | undefined { return dotIndex > 0 ? filename.slice(0, dotIndex) : undefined } -async function resolveExternal( - clients: ResolveClients, - uri: string, -): Promise { - /* - * getLinkMeta still takes the bridge agent (not yet migrated); it only reads - * a service URL from it that LINK_META_PROXY ignores. Keep threading the - * agent here until link-meta migrates. - */ - const result = await getLinkMeta(clients.agent, uri) +async function resolveExternal(uri: string): Promise { + const result = await getLinkMeta(uri) return { type: 'external', uri: result.url, diff --git a/src/lib/link-meta/link-meta.ts b/src/lib/link-meta/link-meta.ts index ab95cd9b35..72c43593cf 100644 --- a/src/lib/link-meta/link-meta.ts +++ b/src/lib/link-meta/link-meta.ts @@ -1,7 +1,6 @@ import {LINK_META_PROXY} from '#/lib/constants' import {getGiphyMetaUri} from '#/lib/strings/embed-player' import {parseStarterPackUri} from '#/lib/strings/starter-pack' -import {type SessionAgent} from '#/state/session' import {type app} from '#/lexicons' import {isBskyAppUrl} from '../strings/url-helpers' @@ -31,7 +30,6 @@ export interface LinkMeta { } export async function getLinkMeta( - agent: SessionAgent, url: string, timeout = 15e3, ): Promise { @@ -80,9 +78,7 @@ export async function getLinkMeta( try { const response = await fetch( - `${LINK_META_PROXY(agent.serviceUrl.toString() || '')}${encodeURIComponent( - url, - )}`, + `${LINK_META_PROXY('')}${encodeURIComponent(url)}`, {signal: controller.signal}, ) diff --git a/src/lib/moderation/useLabelInfo.ts b/src/lib/moderation/useLabelInfo.ts index a766154667..b4bac2c567 100644 --- a/src/lib/moderation/useLabelInfo.ts +++ b/src/lib/moderation/useLabelInfo.ts @@ -12,7 +12,6 @@ import { } from '#/lib/moderation/useGlobalLabelStrings' import {useLabelDefinitions} from '#/state/preferences' import {type app, type com} from '#/lexicons' -import {toLex} from '#/types/bsky' export interface LabelInfo { label: com.atproto.label.defs.Label @@ -23,26 +22,14 @@ export interface LabelInfo { export function useLabelInfo(label: com.atproto.label.defs.Label): LabelInfo { const {i18n} = useLingui() - /* - * TODO(phase4): drop the `toLex` casts once `useLabelDefinitions` - * (state/preferences/label-defs) emits `#/lexicons` / `@bsky.app/sdk` - * moderation types. It still returns old `@atproto/api` - * `InterpretedLabelValueDefinition` / `LabelerViewDetailed`, which are - * structurally identical to the SDK/lexicon ones modulo branded strings. - */ const {labelDefs, labelers} = useLabelDefinitions() - const def = getDefinition( - toLex>(labelDefs), - label, - ) + const def = getDefinition(labelDefs, label) const globalLabelStrings = useGlobalLabelStrings() return { label, def, strings: getLabelStrings(i18n.locale, globalLabelStrings, def), - labeler: toLex(labelers).find( - labeler => label.src === labeler.creator.did, - ), + labeler: labelers.find(labeler => label.src === labeler.creator.did), } } diff --git a/src/lib/moderation/useModerationCauseDescription.ts b/src/lib/moderation/useModerationCauseDescription.ts index 71415da158..c3e7d19640 100644 --- a/src/lib/moderation/useModerationCauseDescription.ts +++ b/src/lib/moderation/useModerationCauseDescription.ts @@ -13,8 +13,6 @@ import {type Props as SVGIconProps} from '#/components/icons/common' import {EyeSlash_Stroke2_Corner0_Rounded as EyeSlash} from '#/components/icons/EyeSlash' import {Warning_Stroke2_Corner0_Rounded as Warning} from '#/components/icons/Warning' import {type AppModerationCause} from '#/components/Pills' -import {type com} from '#/lexicons' -import {toLex} from '#/types/bsky' import {useGlobalLabelStrings} from './useGlobalLabelStrings' import {getDefinition, getLabelStrings} from './useLabelInfo' @@ -129,18 +127,7 @@ export function useModerationCauseDescription( } } if (cause.type === 'label') { - /* - * TODO(phase4): drop `toLex` once `useLabelDefinitions` and the label - * cause type share the `#/lexicons` label shape. `labelDefs` still comes - * from the old `@atproto/api`-typed producer and `cause.label` is the SDK - * label; both are structurally identical to the `#/lexicons` label. - */ - const def = - cause.labelDef || - getDefinition( - toLex[0]>(labelDefs), - toLex(cause.label), - ) + const def = cause.labelDef || getDefinition(labelDefs, cause.label) const strings = getLabelStrings(i18n.locale, globalLabelStrings, def) const labeler = labelers.find(l => l.creator.did === cause.label.src) let source = labeler diff --git a/src/screens/Messages/Conversation.tsx b/src/screens/Messages/Conversation.tsx index 27be5d0c18..06224cb2a6 100644 --- a/src/screens/Messages/Conversation.tsx +++ b/src/screens/Messages/Conversation.tsx @@ -46,7 +46,7 @@ import {Error} from '#/components/Error' import * as Layout from '#/components/Layout' import {IS_LIQUID_GLASS} from '#/env' import {chat} from '#/lexicons' -import {isType, toLex} from '#/types/bsky' +import {isType} from '#/types/bsky' import {ChatDisabled} from './components/ChatDisabled' import {ChatEnded} from './components/ChatEnded' import {ChatLocked} from './components/ChatLocked' @@ -228,8 +228,7 @@ function InnerReady({ const moderationOpts = useModerationOpts() const primaryMemberModeration = useMemo(() => { if (!primaryMember || !moderationOpts) return null - // TODO(phase4): drop toLex once useMaybeProfileShadow emits #/lexicons views - return moderateProfile(toLex(primaryMember), moderationOpts) + return moderateProfile(primaryMember, moderationOpts) }, [primaryMember, moderationOpts]) const header = diff --git a/src/screens/Messages/ConversationSettings/Member.tsx b/src/screens/Messages/ConversationSettings/Member.tsx index 823182e689..ad6fdc6136 100644 --- a/src/screens/Messages/ConversationSettings/Member.tsx +++ b/src/screens/Messages/ConversationSettings/Member.tsx @@ -21,7 +21,6 @@ import * as ProfileCard from '#/components/ProfileCard' import * as Prompt from '#/components/Prompt' import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' -import {toLex} from '#/types/bsky' import {MemberMenu} from './MemberMenu' import {RemoveMemberPrompt} from './prompts' import {StatusBadge} from './StatusBadge' @@ -81,8 +80,7 @@ export function Member({ return } - // TODO(phase4): drop toLex once useProfileShadow emits #/lexicons views - const moderation = moderateProfile(toLex(profile), moderationOpts) + const moderation = moderateProfile(profile, moderationOpts) const isDeletedAccount = profile.handle === 'missing.invalid' const displayName = isDeletedAccount @@ -108,13 +106,10 @@ export function Member({ } const joinedReason = profile.kind?.addedBy - ? // TODO(phase4): drop toLex once addedBy emits #/lexicons views - l`Added by ${createSanitizedDisplayName( + ? l`Added by ${createSanitizedDisplayName( profile.kind.addedBy, true, - moderateProfile(toLex(profile.kind.addedBy), moderationOpts).ui( - 'displayName', - ), + moderateProfile(profile.kind.addedBy, moderationOpts).ui('displayName'), )}` : l`Added by invite link` diff --git a/src/screens/Messages/JoinRequest.tsx b/src/screens/Messages/JoinRequest.tsx index 4c9adf1ce0..f2cb6b67dc 100644 --- a/src/screens/Messages/JoinRequest.tsx +++ b/src/screens/Messages/JoinRequest.tsx @@ -187,9 +187,8 @@ export function JoinRequest({setScreenState}: Props) { {createSanitizedDisplayName( joinLinkPreview.owner, true, - // TODO(phase4): drop toLex once join link preview emits #/lexicons views moderateProfile( - bsky.toLex(joinLinkPreview.owner), + joinLinkPreview.owner, moderationOpts, ).ui('displayName'), )} @@ -224,14 +223,12 @@ export function JoinRequest({setScreenState}: Props) { ? l`Sign in to request access to this group chat.` : l`Sign in to accept invite.`}{' '} {joinLinkPreview.joinRule === 'followedByOwner' && - // TODO(phase4): drop toLex once join link preview emits #/lexicons views l`Only people ${createSanitizedDisplayName( joinLinkPreview.owner, true, - moderateProfile( - bsky.toLex(joinLinkPreview.owner), - moderationOpts, - ).ui('displayName'), + moderateProfile(joinLinkPreview.owner, moderationOpts).ui( + 'displayName', + ), )} follows can join.`} diff --git a/src/screens/Messages/components/ChatListItem.tsx b/src/screens/Messages/components/ChatListItem.tsx index 1c107b7d0c..9df3237c3d 100644 --- a/src/screens/Messages/components/ChatListItem.tsx +++ b/src/screens/Messages/components/ChatListItem.tsx @@ -125,8 +125,7 @@ function DirectChatItem({ const {isWithinLeftPanel} = useIsWithinSplitView() const moderation = useMemo( - // TODO(phase4): drop toLex once useProfileShadow emits #/lexicons views - () => moderateProfile(bsky.toLex(profile), moderationOpts), + () => moderateProfile(profile, moderationOpts), [profile, moderationOpts], ) @@ -193,10 +192,7 @@ function GroupChatItem({ const moderation = useMemo( () => - groupOwner - ? // TODO(phase4): drop toLex once useMaybeProfileShadow emits #/lexicons views - moderateProfile(bsky.toLex(groupOwner), moderationOpts) - : undefined, + groupOwner ? moderateProfile(groupOwner, moderationOpts) : undefined, [groupOwner, moderationOpts], ) @@ -423,15 +419,7 @@ function BaseChatItem({ for (const member of convo.view.members) { unstableCacheProfileView(queryClient, member) } - /* - * `convo.view` comes from the still-old-typed `#/components/dms/util` - * (migrates in a later task) while the convo cache is now keyed on the - * lexicon ConvoView. TODO(phase4): drop toLex once dms/util migrates. - */ - precacheConvoQuery( - queryClient, - bsky.toLex(convo.view), - ) + precacheConvoQuery(queryClient, convo.view) void decrementBadgeCount(convo.view.unreadCount) if (isDeletedAccount) { e.preventDefault() @@ -525,10 +513,7 @@ function BaseChatItem({ } onPressIn={() => // see onPress: old-typed dms/util view into the new-typed cache - precacheConvoQuery( - queryClient, - bsky.toLex(convo.view), - ) + precacheConvoQuery(queryClient, convo.view) } onPress={onPress} onLongPress={showMenu && IS_NATIVE ? onLongPress : undefined} diff --git a/src/screens/Messages/components/ChatStatusInfo.tsx b/src/screens/Messages/components/ChatStatusInfo.tsx index b1e052f005..1910159a49 100644 --- a/src/screens/Messages/components/ChatStatusInfo.tsx +++ b/src/screens/Messages/components/ChatStatusInfo.tsx @@ -17,7 +17,6 @@ import {ProfileBadges} from '#/components/ProfileBadges' import {usePromptControl} from '#/components/Prompt' import {Text} from '#/components/Typography' import type * as bsky from '#/types/bsky' -import {toLex} from '#/types/bsky' import {AcceptChatButton, DeleteChatButton, RejectMenu} from './RequestButtons' export function ChatStatusInfo({convoState}: {convoState: ActiveConvoStates}) { @@ -115,8 +114,7 @@ function InviterHeader({ const t = useTheme() const profile = useProfileShadow(profileUnshadowed) const moderation = useMemo( - // TODO(phase4): drop toLex once useProfileShadow emits #/lexicons views - () => moderateProfile(toLex(profile), moderationOpts), + () => moderateProfile(profile, moderationOpts), [profile, moderationOpts], ) const displayName = createSanitizedDisplayName( diff --git a/src/screens/Messages/components/InviteLinkDialog.tsx b/src/screens/Messages/components/InviteLinkDialog.tsx index 9ebef4c9e5..c30f5dac55 100644 --- a/src/screens/Messages/components/InviteLinkDialog.tsx +++ b/src/screens/Messages/components/InviteLinkDialog.tsx @@ -34,7 +34,6 @@ import {Text} from '#/components/Typography' import {useAnalytics} from '#/analytics' import {IS_WEB} from '#/env' import {type chat} from '#/lexicons' -import {toLex} from '#/types/bsky' import {CopyTextButton} from './CopyTextButton' import {EditTextButton} from './EditTextButton' @@ -69,8 +68,7 @@ export function InviteLinkDialog({ const ownerName = createSanitizedDisplayName( owner, false, - // TODO(phase4): drop toLex once GroupConvoMember emits #/lexicons views - moderateProfile(toLex(owner), moderationOpts).ui('displayName'), + moderateProfile(owner, moderationOpts).ui('displayName'), ) const {joinLink} = convo.details diff --git a/src/screens/Messages/components/MessageComposer.tsx b/src/screens/Messages/components/MessageComposer.tsx index 1e03d3f66e..5adc4ddb1c 100644 --- a/src/screens/Messages/components/MessageComposer.tsx +++ b/src/screens/Messages/components/MessageComposer.tsx @@ -38,7 +38,6 @@ import {Loader} from '#/components/Loader' import * as Toast from '#/components/Toast' import {IS_ANDROID, IS_IOS, IS_LIQUID_GLASS, IS_NATIVE, IS_WEB} from '#/env' import {type chat} from '#/lexicons' -import * as bsky from '#/types/bsky' import {type MessageEmbedState} from './MessageInputEmbed' const MIN_HEIGHT = 40 @@ -70,15 +69,7 @@ export function MessageComposer({ const {getDraft, clearDraft} = useMessageDraft() const composerInternalApiRef = useComposerInternalApiRef() const {replyTo: replyToOld, clearReply} = useMessageReplies() - /* - * `useMessageReplies` (`#/components/dms`, migrates in a later task) still - * emits the old `@atproto/api` MessageView; the send path is typed on the - * lexicon view. Structurally identical modulo branded strings. - * TODO(phase4): drop toLex once dms/MessageReplies migrates. - */ - const replyTo = bsky.toLex( - replyToOld, - ) + const replyTo = replyToOld const [text, setText] = useState(getDraft) useSaveMessageDraft(text) diff --git a/src/screens/Messages/components/MessagesList.tsx b/src/screens/Messages/components/MessagesList.tsx index a0f78b4178..0cada1a9f2 100644 --- a/src/screens/Messages/components/MessagesList.tsx +++ b/src/screens/Messages/components/MessagesList.tsx @@ -569,24 +569,18 @@ export function MessagesList({ try { const post = await getPost({uri: embedState.uri}) if (post) { - /* - * `post` comes from the still-old-typed `useGetPost` producer - * (migrates in a later task), so its uri/view shapes carry plain - * strings where the lexicon types are branded. TODO(phase4): drop - * toLex once that producer migrates. - */ - embed = bsky.toLex<$Typed>({ + embed = { $type: 'app.bsky.embed.record', record: { uri: post.uri, cid: post.cid, }, - }) + } - embedView = bsky.toLex<$Typed>({ + embedView = { $type: 'app.bsky.embed.record#view', record: createEmbedViewRecordFromPost(post), - }) + } stripLinkFacet(uri => { if (!isBskyPostUrl(uri)) return false @@ -611,14 +605,10 @@ export function MessagesList({ const joinLinkPreview = await getJoinLinkPreview({code, hasSession}) if (joinLinkPreview) { - /* - * The preview comes from the still-old-typed `join-links.ts` query - * (migrates in a later task). TODO(phase4): drop toLex once it does. - */ - embedView = bsky.toLex<$Typed>({ + embedView = { $type: 'chat.bsky.embed.joinLink#view', joinLinkPreview, - }) + } } stripLinkFacet(uri => getChatInviteCodeFromUrl(uri) === code) diff --git a/src/screens/Messages/components/MessagesListInfoPanel.tsx b/src/screens/Messages/components/MessagesListInfoPanel.tsx index c2e276879f..9dffaaea5d 100644 --- a/src/screens/Messages/components/MessagesListInfoPanel.tsx +++ b/src/screens/Messages/components/MessagesListInfoPanel.tsx @@ -16,7 +16,6 @@ import {Person_Stroke2_Corner2_Rounded as PersonIcon} from '#/components/icons/P import {ProfileBadges} from '#/components/ProfileBadges' import * as ProfileCard from '#/components/ProfileCard' import {Text} from '#/components/Typography' -import {toLex} from '#/types/bsky' export function MessagesListInfoPanel({ convo, @@ -35,11 +34,10 @@ export function MessagesListInfoPanel({ )[0] const handle = sanitizeHandle(profile.handle, '@') const displayName = moderationOpts - ? // TODO(phase4): drop toLex once convo members emit #/lexicons views - createSanitizedDisplayName( + ? createSanitizedDisplayName( profile, true, - moderateProfile(toLex(profile), moderationOpts).ui('displayName'), + moderateProfile(profile, moderationOpts).ui('displayName'), ) : handle const profileLink = diff --git a/src/screens/Messages/components/RequestButtons.tsx b/src/screens/Messages/components/RequestButtons.tsx index 0161d5351f..30de66d1d7 100644 --- a/src/screens/Messages/components/RequestButtons.tsx +++ b/src/screens/Messages/components/RequestButtons.tsx @@ -41,7 +41,6 @@ import * as Menu from '#/components/Menu' import {ReportDialog} from '#/components/moderation/ReportDialog' import * as Toast from '#/components/Toast' import {type chat} from '#/lexicons' -import * as bsky from '#/types/bsky' export function RejectMenu({ convo, @@ -229,18 +228,10 @@ export function AcceptChatButton({ onMutate: () => { onAcceptConvo?.() if (currentScreen === 'list') { - /* - * `convo` is the old-typed view threaded from `#/components/dms/util` - * consumers while the convo cache is now keyed on the lexicon - * ConvoView. TODO(phase4): drop toLex once this file's props flip. - */ - precacheConvoQuery( - queryClient, - bsky.toLex({ - ...convo, - status: 'accepted', - }), - ) + precacheConvoQuery(queryClient, { + ...convo, + status: 'accepted', + }) navigation.navigate('MessagesConversation', { conversation: convo.id, accept: true, diff --git a/src/screens/PostThread/components/LikesStat.tsx b/src/screens/PostThread/components/LikesStat.tsx index 667e150b67..ef0a78fbee 100644 --- a/src/screens/PostThread/components/LikesStat.tsx +++ b/src/screens/PostThread/components/LikesStat.tsx @@ -16,7 +16,6 @@ import {ProfileHoverCard} from '#/components/ProfileHoverCard' import {Text} from '#/components/Typography' import {useAnalytics} from '#/analytics' import {type app} from '#/lexicons' -import {toLex} from '#/types/bsky' const AVI_SIZE = 20 @@ -94,8 +93,7 @@ export function KnownLikers({post}: {post: AppBskyFeedDefs.PostView}) { .map(like => like.actor) .map(actor => ({ actor, - // TODO(phase4): drop toLex once useLikedBySampleQuery emits #/lexicons views - moderation: moderateProfile(toLex(actor), moderationOpts), + moderation: moderateProfile(actor, moderationOpts), })) .filter(({actor, moderation}) => { const modui = moderation.ui('profileList') diff --git a/src/screens/Profile/Header/ProfileHeaderLabeler.tsx b/src/screens/Profile/Header/ProfileHeaderLabeler.tsx index 608e7faca7..d5341e2ad7 100644 --- a/src/screens/Profile/Header/ProfileHeaderLabeler.tsx +++ b/src/screens/Profile/Header/ProfileHeaderLabeler.tsx @@ -33,7 +33,6 @@ import {Text} from '#/components/Typography' import {useAnalytics} from '#/analytics' import {IS_IOS} from '#/env' import {type app} from '#/lexicons' -import {toLex} from '#/types/bsky' import {ProfileHeaderDisplayName} from './DisplayName' import {EditProfileDialog} from './EditProfileDialog' import {ProfileHeaderHandle} from './Handle' @@ -67,7 +66,7 @@ let ProfileHeaderLabeler = ({ const isSelf = currentAccount?.did === profile.did const moderation = useMemo( - () => moderateProfile(toLex(profile), moderationOpts), + () => moderateProfile(profile, moderationOpts), [profile, moderationOpts], ) const {mutateAsync: likeMod, isPending: isLikePending} = useLikeMutation() diff --git a/src/screens/Profile/Header/ProfileHeaderStandard.tsx b/src/screens/Profile/Header/ProfileHeaderStandard.tsx index 480c10d8bb..b8cba7c4ce 100644 --- a/src/screens/Profile/Header/ProfileHeaderStandard.tsx +++ b/src/screens/Profile/Header/ProfileHeaderStandard.tsx @@ -40,7 +40,6 @@ import {IS_IOS, IS_NATIVE} from '#/env' import {InviteFriendsDialog} from '#/features/inviteFriends' import {useActorStatus} from '#/features/liveNow' import {type app} from '#/lexicons' -import {toLex} from '#/types/bsky' import {GermButton} from '../components/GermButton' import {ProfileHeaderDisplayName} from './DisplayName' import {EditProfileDialog} from './EditProfileDialog' @@ -69,7 +68,7 @@ let ProfileHeaderStandard = ({ const {currentAccount} = useSession() const {_} = useLingui() const moderation = useMemo( - () => moderateProfile(toLex(profile), moderationOpts), + () => moderateProfile(profile, moderationOpts), [profile, moderationOpts], ) const [, queueUnblock] = useProfileBlockMutationQueue(profile) diff --git a/src/screens/Profile/Header/index.tsx b/src/screens/Profile/Header/index.tsx index fc46d9c2ed..dfd84b3530 100644 --- a/src/screens/Profile/Header/index.tsx +++ b/src/screens/Profile/Header/index.tsx @@ -22,7 +22,6 @@ import {Header} from '#/components/Layout' import * as ProfileCard from '#/components/ProfileCard' import {IS_NATIVE} from '#/env' import {type app} from '#/lexicons' -import {toLex} from '#/types/bsky' import { HeaderLabelerButtons, ProfileHeaderLabeler, @@ -112,8 +111,7 @@ const MinimalHeader = memo(function MinimalHeader({ const profile = useProfileShadow(profileUnshadowed) const moderationOpts = useModerationOpts() const moderation = useMemo( - () => - moderationOpts ? moderateProfile(toLex(profile), moderationOpts) : null, + () => (moderationOpts ? moderateProfile(profile, moderationOpts) : null), [moderationOpts, profile], ) const [visible, setVisible] = useState(false) diff --git a/src/screens/ProfileList/components/Header.tsx b/src/screens/ProfileList/components/Header.tsx index 66c0844238..9a537429c0 100644 --- a/src/screens/ProfileList/components/Header.tsx +++ b/src/screens/ProfileList/components/Header.tsx @@ -24,7 +24,6 @@ import {RichText} from '#/components/RichText' import * as Toast from '#/components/Toast' import {useAnalytics} from '#/analytics' import {type app} from '#/lexicons' -import {toLex} from '#/types/bsky' import {MoreOptionsMenu} from './MoreOptionsMenu' import {SubscribeMenu} from './SubscribeMenu' @@ -130,8 +129,7 @@ export function Header({ list.description ? new RichTextAPI({ text: list.description, - // TODO(phase4): drop toLex once the list view producer emits #/lexicons facets - facets: toLex(list.descriptionFacets), + facets: list.descriptionFacets, }) : undefined, [list], diff --git a/src/screens/ProfileList/index.tsx b/src/screens/ProfileList/index.tsx index bb53af5c46..d70be63171 100644 --- a/src/screens/ProfileList/index.tsx +++ b/src/screens/ProfileList/index.tsx @@ -39,7 +39,6 @@ import {Loader} from '#/components/Loader' import * as Hider from '#/components/moderation/Hider' import {IS_WEB} from '#/env' import {type app} from '#/lexicons' -import {toLex} from '#/types/bsky' import {AboutSection} from './AboutSection' import {ErrorScreen} from './components/ErrorScreen' import {Header} from './components/Header' @@ -167,8 +166,7 @@ function ProfileListScreenLoaded({ const [headerHeight, setHeaderHeight] = useState(null) const moderation = useMemo(() => { - // TODO(phase4): drop toLex once ListView prop emits #/lexicons views - return moderateUserList(toLex(list), moderationOpts) + return moderateUserList(list, moderationOpts) }, [list, moderationOpts]) useSetTitle(isHidden ? _(msg`List Hidden`) : list.name) diff --git a/src/screens/Search/components/SearchHistory.tsx b/src/screens/Search/components/SearchHistory.tsx index 07086e48ef..4a23cf4956 100644 --- a/src/screens/Search/components/SearchHistory.tsx +++ b/src/screens/Search/components/SearchHistory.tsx @@ -22,7 +22,6 @@ import {ProfileBadges} from '#/components/ProfileBadges' import {Text} from '#/components/Typography' import {useAnalytics} from '#/analytics' import type * as bsky from '#/types/bsky' -import {toLex} from '#/types/bsky' export function SearchHistory({ searchHistory, @@ -207,8 +206,7 @@ function RecentProfileItem({ const {t: l} = useLingui() const width = 80 - // TODO(phase4): drop toLex once profile prop emits #/lexicons views - const moderation = moderateProfile(toLex(profile), moderationOpts) + const moderation = moderateProfile(profile, moderationOpts) const name = sanitizeDisplayName( profile.displayName || sanitizeHandle(profile.handle), moderation.ui('displayName'), diff --git a/src/screens/Search/modules/ExploreTrendingTopics.tsx b/src/screens/Search/modules/ExploreTrendingTopics.tsx index 51b69e64de..c8e0ee20ec 100644 --- a/src/screens/Search/modules/ExploreTrendingTopics.tsx +++ b/src/screens/Search/modules/ExploreTrendingTopics.tsx @@ -29,7 +29,6 @@ import {Text} from '#/components/Typography' import {useAnalytics} from '#/analytics' import {type app} from '#/lexicons' import * as ModuleHeader from '../components/ModuleHeader' -import {toLex} from '#/types/bsky' const IMAGE_SIZE = 56 @@ -307,8 +306,7 @@ function useModerateTrendingActors( return actors .filter(actor => { - // TODO(phase4): drop toLex once TrendView actors emit #/lexicons views - const decision = moderateProfile(toLex(actor), moderationOpts) + const decision = moderateProfile(actor, moderationOpts) return !decision.ui('avatar').filter && !decision.ui('avatar').blur }) .slice(0, 3) diff --git a/src/screens/Settings/Settings.tsx b/src/screens/Settings/Settings.tsx index b8fc6002e5..2a8e586289 100644 --- a/src/screens/Settings/Settings.tsx +++ b/src/screens/Settings/Settings.tsx @@ -70,7 +70,6 @@ import {useActorStatus} from '#/features/liveNow' import {type app} from '#/lexicons' import {device, useStorage} from '#/storage' import {useActivitySubscriptionsNudged} from '#/storage/hooks/activity-subscriptions-nudged' -import {toLex} from '#/types/bsky' type Props = NativeStackScreenProps export function SettingsScreen({}: Props) { @@ -331,8 +330,7 @@ function ProfilePreview({ if (!moderationOpts) return null - // TODO(phase4): drop toLex once ProfileViewDetailed prop emits #/lexicons views - const moderation = moderateProfile(toLex(profile), moderationOpts) + const moderation = moderateProfile(profile, moderationOpts) const displayName = sanitizeDisplayName( profile.displayName || sanitizeHandle(profile.handle), moderation.ui('displayName'), @@ -639,10 +637,7 @@ function AccountRow({ - // TODO(phase4): drop toLex once feed-manip is migrated off // @atproto/api and yields lex-typed slice items. - moderatePost( - bsky.toLex(item.post), - moderationOpts!, - ), + moderatePost(item.post, moderationOpts!), ) // apply moderation filters @@ -236,19 +232,12 @@ export function useFeedPreviews( const feedPostSliceItem: FeedPostSliceItem = { _reactKey: `${item._reactKey}-${i}-${subItem.post.uri}`, uri: subItem.post.uri, - // TODO(phase4): drop toLex once feed-manip is migrated // off @atproto/api and yields lex-typed slice items. - post: bsky.toLex( - subItem.post, - ), - record: bsky.toLex( - subItem.record, - ), + post: subItem.post, + record: subItem.record, moderation: moderations[i], parentAuthor: subItem.parentAuthor - ? bsky.toLex( - subItem.parentAuthor, - ) + ? subItem.parentAuthor : undefined, isParentBlocked: subItem.isParentBlocked, isParentNotFound: subItem.isParentNotFound, diff --git a/src/state/queries/messages/add-group-members.ts b/src/state/queries/messages/add-group-members.ts index fbbffd5acb..138869f0f0 100644 --- a/src/state/queries/messages/add-group-members.ts +++ b/src/state/queries/messages/add-group-members.ts @@ -57,33 +57,24 @@ export function useAddGroupMembers( chat.bsky.actor.defs.ProfileViewBasic[] >(listConvoMembersQueryKey(convoId)) - /* - * The profile views come from producers that still emit the old - * `@atproto/api` shapes (useProfileQuery migrates in a later task), while - * the chat caches are now typed on the lexicon views. Structurally - * identical modulo branded strings. TODO(phase4): drop toLex once those - * producers migrate. - */ const addedBy: chat.bsky.actor.defs.ProfileViewBasic | undefined = myProfile - ? bsky.toLex({ + ? { ...myProfile, $type: 'chat.bsky.actor.defs#profileViewBasic', - }) + } : undefined const optimisticMembers: chat.bsky.actor.defs.ProfileViewBasic[] = - profiles.map(profile => - bsky.toLex({ - ...profile, - $type: 'chat.bsky.actor.defs#profileViewBasic', - kind: { - $type: 'chat.bsky.actor.defs#groupConvoMember', - role: 'standard', - addedBy, - }, - }), - ) + profiles.map(profile => ({ + ...profile, + $type: 'chat.bsky.actor.defs#profileViewBasic', + kind: { + $type: 'chat.bsky.actor.defs#groupConvoMember', + role: 'standard', + addedBy, + }, + })) queryClient.setQueryData( CONVO_KEY(convoId), diff --git a/src/state/queries/notifications/feed.ts b/src/state/queries/notifications/feed.ts index 57b4d6c29b..b985e614ae 100644 --- a/src/state/queries/notifications/feed.ts +++ b/src/state/queries/notifications/feed.ts @@ -297,11 +297,8 @@ export function* findAllPostsInQueryData( if (bsky.isType(app.bsky.feed.defs.postView, item.subject)) { const quotedPost = getEmbeddedPost(item.subject?.embed) if (quotedPost && didOrHandleUriMatches(atUri, quotedPost)) { - // TODO(phase4): drop toLex once ../util is migrated and // embedViewRecordToPostView returns the lexicon PostView. - yield bsky.toLex( - embedViewRecordToPostView(quotedPost), - ) + yield embedViewRecordToPostView(quotedPost) } } } diff --git a/src/state/queries/post-feed.ts b/src/state/queries/post-feed.ts index beccf10415..0edb16faf2 100644 --- a/src/state/queries/post-feed.ts +++ b/src/state/queries/post-feed.ts @@ -288,9 +288,8 @@ export function usePostFeedQuery( .map(slice => { const moderations = slice.items.map(item => moderatePost( - // TODO(phase4): drop toLex once feed-manip is migrated // off @atproto/api and yields lex-typed slice items. - bsky.toLex(item.post), + item.post, moderationOpts!, ), ) @@ -342,19 +341,12 @@ export function usePostFeedQuery( const feedPostSliceItem: FeedPostSliceItem = { _reactKey: `${slice._reactKey}-${i}-${item.post.uri}`, uri: item.post.uri, - // TODO(phase4): drop toLex once feed-manip is migrated // off @atproto/api and yields lex-typed slice items. - post: bsky.toLex( - item.post, - ), - record: bsky.toLex( - item.record, - ), + post: item.post, + record: item.record, moderation: moderations[i], parentAuthor: item.parentAuthor - ? bsky.toLex( - item.parentAuthor, - ) + ? item.parentAuthor : undefined, isParentBlocked: item.isParentBlocked, isParentNotFound: item.isParentNotFound, diff --git a/src/state/queries/preferences/index.ts b/src/state/queries/preferences/index.ts index c2576408e1..203ae3635c 100644 --- a/src/state/queries/preferences/index.ts +++ b/src/state/queries/preferences/index.ts @@ -44,7 +44,6 @@ import {useAgeAssurance} from '#/ageAssurance' import {makeAgeRestrictedModerationPrefs} from '#/ageAssurance/util' import {useAnalytics} from '#/analytics' import {app} from '#/lexicons' -import {toLex} from '#/types/bsky' export * from '#/state/queries/preferences/const' export * from '#/state/queries/preferences/moderation' @@ -110,16 +109,8 @@ export function usePreferencesQuery() { ) { data = { ...data, - /* - * TODO(phase4): drop the toLex bridges once - * `#/ageAssurance/util` (makeAgeRestrictedModerationPrefs) sources - * `ModerationPrefs` from `@bsky.app/sdk/moderation` instead of - * `@atproto/api`. The two shapes differ only in scalar branding - * (e.g. MutedWord.actorTarget's UnknownString), so the values are - * structurally interchangeable at this boundary. - */ - moderationPrefs: toLex( - makeAgeRestrictedModerationPrefs(toLex(data.moderationPrefs)), + moderationPrefs: makeAgeRestrictedModerationPrefs( + data.moderationPrefs, ), } } diff --git a/src/state/queries/resolve-link.ts b/src/state/queries/resolve-link.ts index be499d1f23..491e12bff8 100644 --- a/src/state/queries/resolve-link.ts +++ b/src/state/queries/resolve-link.ts @@ -7,7 +7,7 @@ import { resolveLink, } from '#/lib/api/resolve' import {STALE} from '#/state/queries/index' -import {useAgent, useChatClient, useLexClient} from '#/state/session' +import {useChatClient, useLexClient} from '#/state/session' import {type Gif} from '#/features/gifPicker/types' export const RQKEY_LINK_ROOT = 'resolve-link' @@ -26,15 +26,13 @@ export function resolveLinkQueryOptions(clients: ResolveClients, url: string) { /** * Bundle the clients the link resolver needs from the session hooks. The - * appview client serves the `app.bsky.*` reads and handle resolution, the chat - * client serves group join-link previews, and the bridge agent is still passed - * through to the not-yet-migrated `getLinkMeta`. + * appview client serves the `app.bsky.*` reads and handle resolution, and the + * chat client serves group join-link previews. */ export function useResolveClients(): ResolveClients { const appview = useLexClient() const chat = useChatClient() - const agent = useAgent() - return {appview, chat, agent} + return {appview, chat} } export function useResolveLinkQuery(url: string) { diff --git a/src/state/queries/usePostThread/queryCache.ts b/src/state/queries/usePostThread/queryCache.ts index 5a84bf85a4..afc7465ceb 100644 --- a/src/state/queries/usePostThread/queryCache.ts +++ b/src/state/queries/usePostThread/queryCache.ts @@ -255,27 +255,23 @@ export function* getThreadPlaceholderCandidates( for (let post of findAllPostsInNotifsQueryData(queryClient, uri)) { yield postViewToThreadPlaceholder(post) } - /* - * TODO(phase4): drop toLex once the feed/quote/search/bookmarks/explore - * `findAllPostsInQueryData` generators are migrated to `#/lexicons` types. - */ for (let post of findAllPostsInFeedQueryData(queryClient, uri)) { - yield postViewToThreadPlaceholder(bsky.toLex(post)) + yield postViewToThreadPlaceholder(post) } for (let post of findAllPostsInQuoteQueryData(queryClient, uri)) { - yield postViewToThreadPlaceholder(bsky.toLex(post)) + yield postViewToThreadPlaceholder(post) } for (let post of findAllPostsInSearchQueryData(queryClient, uri)) { - yield postViewToThreadPlaceholder(bsky.toLex(post)) + yield postViewToThreadPlaceholder(post) } for (let post of findAllPostsInBookmarksQueryData(queryClient, uri)) { - yield postViewToThreadPlaceholder(bsky.toLex(post)) + yield postViewToThreadPlaceholder(post) } for (let post of findAllPostsInExploreFeedPreviewsQueryData( queryClient, uri, )) { - yield postViewToThreadPlaceholder(bsky.toLex(post)) + yield postViewToThreadPlaceholder(post) } } @@ -302,11 +298,7 @@ export function* findAllPostsInQueryData( const qp = getEmbeddedPost(item.value.post.embed) if (qp && didOrHandleUriMatches(atUri, qp)) { - /* - * TODO(phase4): drop toLex once `embedViewRecordToPostView` in - * `#/state/queries/util` is migrated to `#/lexicons` types. - */ - yield bsky.toLex(embedViewRecordToPostView(qp)) + yield embedViewRecordToPostView(qp) } } } @@ -335,11 +327,7 @@ export function* findAllProfilesInQueryData( const qp = getEmbeddedPost(item.value.post.embed) if (qp && qp.author.did === did) { - /* - * TODO(phase4): drop toLex once `getEmbeddedPost` in - * `#/state/queries/util` is migrated to `#/lexicons` types. - */ - yield bsky.toLex(qp.author) + yield qp.author } } } diff --git a/src/state/session/index.tsx b/src/state/session/index.tsx index ed483a5044..f872b7d355 100644 --- a/src/state/session/index.tsx +++ b/src/state/session/index.tsx @@ -80,6 +80,7 @@ const ApiContext = createContext({ resumeSession: async () => {}, removeAccount: () => {}, partialRefreshSession: async () => {}, + refreshSession: () => Promise.resolve(undefined), }) ApiContext.displayName = 'SessionApiContext' @@ -344,6 +345,28 @@ export function Provider({children}: React.PropsWithChildren<{}>) { }) }, [store, state, cancelPendingTask]) + const refreshSession = useCallback< + SessionApiContext['refreshSession'] + >(async () => { + const bundle = store.getState().currentAgentState.agent as unknown as + | SessionBundle + | PublicSessionBundle + if (!bundle.session) return undefined // logged out: nothing to refresh + /* + * PasswordSession.refresh() re-runs com.atproto.server.refreshSession + + * getSession. On success the session's onUpdated hook fires, which the + * armed makeSessionHooks wiring maps to an 'update' event; the reducer + * snapshots the refreshed account. No explicit dispatch is needed here. + * The returned snapshot lets callers read post-refresh fields without + * waiting on the (async) reducer update. + */ + await bundle.session.refresh() + return sessionDataToSessionAccount( + bundle.session.session, + bundle.session.session.service, + ) + }, [store]) + const removeAccount = useCallback( account => { addSessionDebugLog({ @@ -443,6 +466,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) { resumeSession, removeAccount, partialRefreshSession, + refreshSession, }), [ createAccount, @@ -452,6 +476,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) { resumeSession, removeAccount, partialRefreshSession, + refreshSession, ], ) diff --git a/src/state/session/types.ts b/src/state/session/types.ts index 8a9afba42c..d83d3de4e6 100644 --- a/src/state/session/types.ts +++ b/src/state/session/types.ts @@ -51,4 +51,15 @@ export type SessionApiContext = { * `persistSessionHandler`. */ partialRefreshSession: () => Promise + /** + * Force a full session refresh (re-runs `com.atproto.server.refreshSession` + * plus `getSession`) and return the refreshed account snapshot, or + * `undefined` when logged out. + * + * The refresh routes through the session's own `refresh()`, whose success + * hook propagates the updated account into state; the returned snapshot lets + * callers read post-refresh fields synchronously without waiting on the + * (async) reducer update. Rejections propagate to the caller. + */ + refreshSession: () => Promise } diff --git a/src/view/com/composer/drafts/state/api.ts b/src/view/com/composer/drafts/state/api.ts index 66aca07d5c..8f4af5178b 100644 --- a/src/view/com/composer/drafts/state/api.ts +++ b/src/view/com/composer/drafts/state/api.ts @@ -12,7 +12,6 @@ import {mimeToExt} from '#/lib/media/video/util' import {shortenLinks} from '#/lib/strings/rich-text-manip' import {type ComposerImage} from '#/state/gallery' import {threadgateAllowUISettingToAllowRecordValue} from '#/state/queries/threadgate/util' -import {createPublicAgent} from '#/state/session/agent' import {getPublicLexClient} from '#/state/session/clients' import { type ComposerState, @@ -141,10 +140,9 @@ async function postDraftToServerPost( // Add quote record embed if (post.embed.quote) { - const agent = createPublicAgent() const publicClient = getPublicLexClient() const resolved = await resolveLink( - {appview: publicClient, chat: publicClient, agent}, + {appview: publicClient, chat: publicClient}, post.embed.quote.uri, ) if (resolved && resolved.type === 'record') { diff --git a/src/view/com/notifications/NotificationFeedItem.tsx b/src/view/com/notifications/NotificationFeedItem.tsx index fa510ded59..88825f29bb 100644 --- a/src/view/com/notifications/NotificationFeedItem.tsx +++ b/src/view/com/notifications/NotificationFeedItem.tsx @@ -148,15 +148,12 @@ let NotificationFeedItem = ({ { profile: item.notification.author, href: makeProfileLink(item.notification.author), - moderation: moderateProfile( - bsky.toLex(item.notification.author), - moderationOpts, - ), + moderation: moderateProfile(item.notification.author, moderationOpts), }, ...(item.additional?.map(({author}) => ({ profile: author, href: makeProfileLink(author), - moderation: moderateProfile(bsky.toLex(author), moderationOpts), + moderation: moderateProfile(author, moderationOpts), })) || []), ].filter( (author, index, arr) => diff --git a/src/view/com/post-thread/PostQuotes.tsx b/src/view/com/post-thread/PostQuotes.tsx index b4b0de2c58..459bbc525e 100644 --- a/src/view/com/post-thread/PostQuotes.tsx +++ b/src/view/com/post-thread/PostQuotes.tsx @@ -73,8 +73,7 @@ export function PostQuotes({uri}: {uri: string}) { ) { return null } - // TODO(phase4): drop toLex once usePostQuotesQuery emits #/lexicons views - const moderation = moderatePost(bsky.toLex(post), moderationOpts) + const moderation = moderatePost(post, moderationOpts) return {post, record: post.record, moderation} }), ) diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx index 96cb6d62c7..42f888f57c 100644 --- a/src/view/com/post/Post.tsx +++ b/src/view/com/post/Post.tsx @@ -61,17 +61,13 @@ export function Post({ record ? new RichTextAPI({ text: record.text, - // TODO(phase4): drop toLex once the post record producer emits #/lexicons facets - facets: bsky.toLex(record.facets), + facets: record.facets, }) : undefined, [record], ) const moderation = useMemo( - () => - moderationOpts - ? moderatePost(bsky.toLex(post), moderationOpts) - : undefined, + () => (moderationOpts ? moderatePost(post, moderationOpts) : undefined), [moderationOpts, post], ) if (postShadowed === POST_TOMBSTONE) { @@ -135,8 +131,7 @@ function PostInner({ text: record.text, author: post.author, embed: post.embed, - // TODO(phase4): drop toLex once the composer state accepts SDK ModerationDecision - moderation: bsky.toLex(moderation), + moderation: moderation, langs: record.langs, }, logContext: 'PostReply', diff --git a/src/view/com/posts/PostFeedItem.tsx b/src/view/com/posts/PostFeedItem.tsx index ef2ca2e3e9..5e5dfa2823 100644 --- a/src/view/com/posts/PostFeedItem.tsx +++ b/src/view/com/posts/PostFeedItem.tsx @@ -99,8 +99,7 @@ export function PostFeedItem({ () => new RichTextAPI({ text: record.text, - // TODO(phase4): drop toLex once the post record producer emits #/lexicons facets - facets: bsky.toLex(record.facets), + facets: record.facets, }), [record], )