finish phase 3: type-only codemod and zero non-bridge @atproto/api imports

Task 8: codemod repointed 150 namespace-type files to #/lexicons
(AppBskyFeedDefs.PostView -> app.bsky.feed.defs.PostView, .Record -> .Main)
plus ~105 hand-fixed consumers (composer/video state, DebugMod, Profile,
onboarding, dialogs). DM_SERVICE_HEADERS deleted; last chat call sites on
the chat client. RichText.tsx flipped to SDK-only. Remaining @atproto/api
importers: the three session bridge files, the deliberate dual-world
matcher in lib/xrpc-error.ts, and test fixtures. toLex boundary casts are
TODO(phase4)-tagged for bridge removal.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Samuel Newman
2026-07-17 02:08:48 +03:00
parent 300a50b69a
commit e7d349bc30
283 changed files with 2029 additions and 1806 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ import {sha256} from 'js-sha256'
import {CID} from 'multiformats/cid'
import * as Hasher from 'multiformats/hashes/hasher'
import {app} from '#/lexicons'
import {type app} from '#/lexicons'
/*
* Client-side CID computation for post records, extracted from the post
+38 -47
View File
@@ -1,17 +1,10 @@
import {
type AppBskyActorDefs,
AppBskyEmbedRecord,
AppBskyEmbedRecordWithMedia,
AppBskyFeedDefs,
AppBskyFeedPost,
} from '@atproto/api'
import {app} from '#/lexicons'
import * as bsky from '#/types/bsky'
import {isPostInLanguage} from '../../locale/helpers'
import {FALLBACK_MARKER_POST} from './feed/home'
import {type ReasonFeedSource} from './feed/types'
type FeedViewPost = AppBskyFeedDefs.FeedViewPost
type FeedViewPost = app.bsky.feed.defs.FeedViewPost
export type FeedTunerFn = (
tuner: FeedTuner,
@@ -20,18 +13,18 @@ export type FeedTunerFn = (
) => FeedViewPostsSlice[]
type FeedSliceItem = {
post: AppBskyFeedDefs.PostView
record: AppBskyFeedPost.Record
parentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
post: app.bsky.feed.defs.PostView
record: app.bsky.feed.post.Main
parentAuthor: app.bsky.actor.defs.ProfileViewBasic | undefined
isParentBlocked: boolean
isParentNotFound: boolean
}
type AuthorContext = {
author: AppBskyActorDefs.ProfileViewBasic
parentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
grandparentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
rootAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
author: app.bsky.actor.defs.ProfileViewBasic
parentAuthor: app.bsky.actor.defs.ProfileViewBasic | undefined
grandparentAuthor: app.bsky.actor.defs.ProfileViewBasic | undefined
rootAuthor: app.bsky.actor.defs.ProfileViewBasic | undefined
}
export class FeedViewPostsSlice {
@@ -53,7 +46,7 @@ export class FeedViewPostsSlice {
this.isOrphan = false
this.isThreadMuted = post.viewer?.threadMuted ?? false
this.feedPostUri = post.uri
if (AppBskyFeedDefs.isPostView(reply?.root)) {
if (bsky.isType(app.bsky.feed.defs.postView, reply?.root)) {
this.rootUri = reply.root.uri
} else {
this.rootUri = post.uri
@@ -68,17 +61,17 @@ export class FeedViewPostsSlice {
this.isFallbackMarker = true
return
}
if (
!AppBskyFeedPost.isRecord(post.record) ||
!bsky.validate(post.record, AppBskyFeedPost.validateRecord)
) {
if (!bsky.matches(app.bsky.feed.post, post.record)) {
return
}
const parent = reply?.parent
const isParentBlocked = AppBskyFeedDefs.isBlockedPost(parent)
const isParentNotFound = AppBskyFeedDefs.isNotFoundPost(parent)
let parentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
if (AppBskyFeedDefs.isPostView(parent)) {
const isParentBlocked = bsky.isType(app.bsky.feed.defs.blockedPost, parent)
const isParentNotFound = bsky.isType(
app.bsky.feed.defs.notFoundPost,
parent,
)
let parentAuthor: app.bsky.actor.defs.ProfileViewBasic | undefined
if (bsky.isType(app.bsky.feed.defs.postView, parent)) {
parentAuthor = parent.author
}
this.items.push({
@@ -100,18 +93,17 @@ export class FeedViewPostsSlice {
return
}
if (
!AppBskyFeedDefs.isPostView(parent) ||
!AppBskyFeedPost.isRecord(parent.record) ||
!bsky.validate(parent.record, AppBskyFeedPost.validateRecord)
!bsky.isType(app.bsky.feed.defs.postView, parent) ||
!bsky.matches(app.bsky.feed.post, parent.record)
) {
this.isOrphan = true
return
}
const root = reply.root
const rootIsView =
AppBskyFeedDefs.isPostView(root) ||
AppBskyFeedDefs.isBlockedPost(root) ||
AppBskyFeedDefs.isNotFoundPost(root)
bsky.isType(app.bsky.feed.defs.postView, root) ||
bsky.isType(app.bsky.feed.defs.blockedPost, root) ||
bsky.isType(app.bsky.feed.defs.notFoundPost, root)
/*
* If the parent is also the root, we just so happen to have the data we
* need to compute if the parent's parent (grandparent) is blocked. This
@@ -124,10 +116,10 @@ export class FeedViewPostsSlice {
: undefined
const grandparentAuthor = reply.grandparentAuthor
const isGrandparentBlocked = Boolean(
grandparent && AppBskyFeedDefs.isBlockedPost(grandparent),
grandparent && bsky.isType(app.bsky.feed.defs.blockedPost, grandparent),
)
const isGrandparentNotFound = Boolean(
grandparent && AppBskyFeedDefs.isNotFoundPost(grandparent),
grandparent && bsky.isType(app.bsky.feed.defs.notFoundPost, grandparent),
)
this.items.unshift({
post: parent,
@@ -142,9 +134,8 @@ export class FeedViewPostsSlice {
// de-deduping
}
if (
!AppBskyFeedDefs.isPostView(root) ||
!AppBskyFeedPost.isRecord(root.record) ||
!bsky.validate(root.record, AppBskyFeedPost.validateRecord)
!bsky.isType(app.bsky.feed.defs.postView, root) ||
!bsky.matches(app.bsky.feed.post, root.record)
) {
this.isOrphan = true
return
@@ -167,14 +158,14 @@ export class FeedViewPostsSlice {
get isQuotePost() {
const embed = this._feedPost.post.embed
return (
AppBskyEmbedRecord.isView(embed) ||
AppBskyEmbedRecordWithMedia.isView(embed)
bsky.isType(app.bsky.embed.record.view, embed) ||
bsky.isType(app.bsky.embed.recordWithMedia.view, embed)
)
}
get isReply() {
return (
AppBskyFeedPost.isRecord(this._feedPost.post.record) &&
bsky.isType(app.bsky.feed.post, this._feedPost.post.record) &&
!!this._feedPost.post.record.reply
)
}
@@ -195,7 +186,7 @@ export class FeedViewPostsSlice {
get isRepost() {
const reason = this._feedPost.reason
return AppBskyFeedDefs.isReasonRepost(reason)
return bsky.isType(app.bsky.feed.defs.reasonRepost, reason)
}
get likeCount() {
@@ -208,18 +199,18 @@ export class FeedViewPostsSlice {
getAuthors(): AuthorContext {
const feedPost = this._feedPost
let author: AppBskyActorDefs.ProfileViewBasic = feedPost.post.author
let parentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
let grandparentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
let rootAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
let author: app.bsky.actor.defs.ProfileViewBasic = feedPost.post.author
let parentAuthor: app.bsky.actor.defs.ProfileViewBasic | undefined
let grandparentAuthor: app.bsky.actor.defs.ProfileViewBasic | undefined
let rootAuthor: app.bsky.actor.defs.ProfileViewBasic | undefined
if (feedPost.reply) {
if (AppBskyFeedDefs.isPostView(feedPost.reply.parent)) {
if (bsky.isType(app.bsky.feed.defs.postView, feedPost.reply.parent)) {
parentAuthor = feedPost.reply.parent.author
}
if (feedPost.reply.grandparentAuthor) {
grandparentAuthor = feedPost.reply.grandparentAuthor
}
if (AppBskyFeedDefs.isPostView(feedPost.reply.root)) {
if (bsky.isType(app.bsky.feed.defs.postView, feedPost.reply.root)) {
rootAuthor = feedPost.reply.root.author
}
}
@@ -514,7 +505,7 @@ function shouldDisplayReplyInFollowing(
}
function isSelfOrFollowing(
profile: AppBskyActorDefs.ProfileViewBasic,
profile: app.bsky.actor.defs.ProfileViewBasic,
userDid: string,
) {
return Boolean(profile.did === userDid || profile.viewer?.following)
+5 -8
View File
@@ -1,8 +1,9 @@
import {type Insets, Platform} from 'react-native'
import {type AppBskyActorDefs, BSKY_LABELER_DID} from '@atproto/api'
import {api} from '@bsky.app/sdk'
import {type ProxyHeaderValue} from '#/state/session/agent'
import {BLUESKY_PROXY_DID, CHAT_PROXY_DID, IS_DEV} from '#/env'
import {BLUESKY_PROXY_DID, IS_DEV} from '#/env'
import {type app} from '#/lexicons'
export const LOCAL_DEV_SERVICE =
Platform.OS === 'android' ? 'http://10.0.2.2:2583' : 'http://localhost:2583'
@@ -173,7 +174,7 @@ export const VIDEO_SAVED_FEED = {
}
export const RECOMMENDED_SAVED_FEEDS: Pick<
AppBskyActorDefs.SavedFeed,
app.bsky.actor.defs.SavedFeed,
'type' | 'value' | 'pinned'
>[] = [DISCOVER_SAVED_FEED, TIMELINE_SAVED_FEED]
@@ -246,12 +247,8 @@ export const BLUESKY_PROXY_HEADER = {
},
}
export const DM_SERVICE_HEADERS = {
'atproto-proxy': `${CHAT_PROXY_DID}#bsky_chat`,
}
export const BLUESKY_MOD_SERVICE_HEADERS = {
'atproto-proxy': `${BSKY_LABELER_DID}#atproto_labeler`,
'atproto-proxy': `${api.moderation.did}#atproto_labeler`,
}
export const BLUESKY_NOTIF_SERVICE_HEADERS = {
+8 -6
View File
@@ -1,11 +1,13 @@
import {type AppBskyFeedGetFeed} from '@atproto/api'
import {toDatetimeString} from '@atproto/syntax'
import {subDays, subMinutes} from 'date-fns'
import {type app} from '#/lexicons'
const DID = `did:plc:z72i7hdynmk6r22z27h6tvur`
const NOW = new Date()
const POST_1_DATE = subMinutes(NOW, 2).toISOString()
const POST_2_DATE = subMinutes(NOW, 4).toISOString()
const POST_3_DATE = subMinutes(NOW, 5).toISOString()
const POST_1_DATE = toDatetimeString(subMinutes(NOW, 2))
const POST_2_DATE = toDatetimeString(subMinutes(NOW, 4))
const POST_3_DATE = toDatetimeString(subMinutes(NOW, 5))
export const DEMO_FEED = {
feed: [
@@ -31,7 +33,7 @@ export const DEMO_FEED = {
issuer: DID,
uri: `at://${DID}/app.bsky.graph.verification/post1`,
isValid: true,
createdAt: subDays(NOW, 11).toISOString(),
createdAt: toDatetimeString(subDays(NOW, 11)),
},
],
verifiedStatus: 'valid',
@@ -197,6 +199,6 @@ export const DEMO_FEED = {
},
},
],
} satisfies AppBskyFeedGetFeed.OutputSchema
} satisfies app.bsky.feed.getFeed.$OutputBody
export const BOTTOM_BAR_AVI = 'https://bsky.social/about/adi/user_avi.jpg'
+1 -1
View File
@@ -1,6 +1,6 @@
import {useEffect} from 'react'
import * as Notifications from 'expo-notifications'
import {AtUri} from '@atproto/api'
import {AtUri} from '@atproto/syntax'
import {useLingui} from '@lingui/react/macro'
import {CommonActions, useNavigation} from '@react-navigation/native'
import {useQueryClient} from '@tanstack/react-query'
+2 -2
View File
@@ -1,7 +1,7 @@
import {useCallback, useRef} from 'react'
import {type AppBskyFeedDefs} from '@atproto/api'
import {type Metrics, useAnalytics} from '#/analytics'
import {type app} from '#/lexicons'
/**
* Hook that returns a callback to track post:view events.
@@ -17,7 +17,7 @@ export function usePostViewTracking(
const seenUrisRef = useRef(new Set<string>())
const trackPostView = useCallback(
(post: AppBskyFeedDefs.PostView) => {
(post: app.bsky.feed.defs.PostView) => {
if (seenUrisRef.current.has(post.uri)) return
seenUrisRef.current.add(post.uri)
+3 -4
View File
@@ -1,9 +1,8 @@
import {type AppBskyEmbedExternal} from '@atproto/api'
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'
export enum LikelyType {
@@ -27,8 +26,8 @@ export interface LinkMeta {
* The AT-URI of the Atmosphere record representing this external content, if
* it exists. Example: a site.standard.document record.
*/
associatedRefs?: AppBskyEmbedExternal.External['associatedRefs']
view?: AppBskyEmbedExternal.View
associatedRefs?: app.bsky.embed.external.External['associatedRefs']
view?: app.bsky.embed.external.View
}
export async function getLinkMeta(
+1 -1
View File
@@ -11,7 +11,7 @@ import {
type VideoUploadTransport,
} from '#/lib/media/video/types'
import {Features, features} from '#/analytics/features'
import {app} from '#/lexicons'
import {type app} from '#/lexicons'
import {MultipartFallbackError, uploadVideoMultipart} from './multipart/upload'
import {getServiceAuthToken, getVideoUploadLimits} from './upload.shared'
import {createVideoEndpointUrl, mimeToExt} from './util'
+1 -1
View File
@@ -10,7 +10,7 @@ import {
type VideoUploadTransport,
} from '#/lib/media/video/types'
import {Features, features} from '#/analytics/features'
import {app} from '#/lexicons'
import {type app} from '#/lexicons'
import {MultipartFallbackError, uploadVideoMultipart} from './multipart/upload'
import {getServiceAuthToken, getVideoUploadLimits} from './upload.shared'
import {createVideoEndpointUrl, mimeToExt} from './util'
+11
View File
@@ -31,6 +31,17 @@ export function createVideoServiceClient(token: string) {
})
}
/**
* An unauthenticated lex {@link Client} scoped to the video service, used for
* public reads like `getJobStatus` polling. Mirrors the old unauthenticated
* `AtpAgent` at `VIDEO_SERVICE`.
*/
export function createTokenlessVideoServiceClient() {
return new Client({
service: VIDEO_SERVICE,
})
}
export function mimeToExt(mimeType: SupportedMimeTypes | (string & {})) {
switch (mimeType) {
case 'video/mp4':
+2 -2
View File
@@ -2,7 +2,6 @@ import {useCallback, useEffect} from 'react'
import {Platform} from 'react-native'
import * as Notifications from 'expo-notifications'
import {getBadgeCountAsync, setBadgeCountAsync} from 'expo-notifications'
import {type AppBskyNotificationRegisterPush} from '@atproto/api'
import debounce from 'lodash.debounce'
import {
@@ -18,6 +17,7 @@ import BackgroundNotificationHandler from '#/../modules/expo-background-notifica
import {useAgeAssurance} from '#/ageAssurance'
import {useAnalytics} from '#/analytics'
import {IS_DEV, IS_NATIVE} from '#/env'
import {type app} from '#/lexicons'
/**
* @private
@@ -37,7 +37,7 @@ async function _registerPushToken({
}
}) {
try {
const payload: AppBskyNotificationRegisterPush.InputSchema = {
const payload: app.bsky.notification.registerPush.$InputBody = {
serviceDid: currentAccount.service?.includes('staging')
? PUBLIC_STAGING_APPVIEW_DID
: PUBLIC_APPVIEW_DID,
+4 -3
View File
@@ -1,6 +1,7 @@
import {type AppBskyGraphDefs, AtUri} from '@atproto/api'
import {AtUri} from '@atproto/syntax'
import {isInvalidHandle} from '#/lib/strings/handles'
import {type app} from '#/lexicons'
export function makeProfileLink(
info: {
@@ -44,8 +45,8 @@ export function makeSearchLink(props: {query: string; from?: 'me' | string}) {
export function makeStarterPackLink(
starterPackOrName:
| AppBskyGraphDefs.StarterPackViewBasic
| AppBskyGraphDefs.StarterPackView
| app.bsky.graph.defs.StarterPackViewBasic
| app.bsky.graph.defs.StarterPackView
| string,
rkey?: string,
) {