[SDK] Remove @atproto/api (#11386)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Samuel Newman
2026-08-13 22:26:22 +03:00
committed by GitHub
parent 54da80dfb0
commit 9fe0084874
391 changed files with 3130 additions and 3589 deletions
+71 -78
View File
@@ -1,13 +1,5 @@
import {
type $Typed,
type AppBskyEmbedRecord,
type ChatBskyActorDefs,
ChatBskyConvoDefs,
type ChatBskyConvoGetLog,
type ChatBskyEmbedJoinLink,
type ChatBskyGroupDefs,
} from '@atproto/api'
import {type Client, XrpcResponseError} from '@atproto/lex'
import {type $Typed, type Client, XrpcResponseError} from '@atproto/lex'
import {type DidString, toDatetimeString} from '@atproto/syntax'
import {EventEmitter} from 'eventemitter3'
import {nanoid} from 'nanoid/non-secure'
@@ -49,7 +41,8 @@ import {
parseConvoView,
} from '#/components/dms/util'
import {IS_NATIVE} from '#/env'
import {chat} from '#/lexicons'
import {type app, chat} from '#/lexicons'
import * as bsky from '#/types/bsky'
const logger = Logger.create(Logger.Context.ConversationAgent)
@@ -65,21 +58,21 @@ export function isConvoItemMessage(
}
function toSystemMessageView(
ev: ChatBskyConvoGetLog.OutputSchema['logs'][number],
): ChatBskyConvoDefs.SystemMessageView | null {
ev: chat.bsky.convo.getLog.$OutputBody['logs'][number],
): chat.bsky.convo.defs.SystemMessageView | null {
const isSystem =
ChatBskyConvoDefs.isLogAddMember(ev) ||
ChatBskyConvoDefs.isLogRemoveMember(ev) ||
ChatBskyConvoDefs.isLogMemberJoin(ev) ||
ChatBskyConvoDefs.isLogMemberLeave(ev) ||
ChatBskyConvoDefs.isLogLockConvo(ev) ||
ChatBskyConvoDefs.isLogUnlockConvo(ev) ||
ChatBskyConvoDefs.isLogLockConvoPermanently(ev) ||
ChatBskyConvoDefs.isLogEditGroup(ev) ||
ChatBskyConvoDefs.isLogCreateJoinLink(ev) ||
ChatBskyConvoDefs.isLogEditJoinLink(ev) ||
ChatBskyConvoDefs.isLogEnableJoinLink(ev) ||
ChatBskyConvoDefs.isLogDisableJoinLink(ev)
bsky.isType(chat.bsky.convo.defs.logAddMember, ev) ||
bsky.isType(chat.bsky.convo.defs.logRemoveMember, ev) ||
bsky.isType(chat.bsky.convo.defs.logMemberJoin, ev) ||
bsky.isType(chat.bsky.convo.defs.logMemberLeave, ev) ||
bsky.isType(chat.bsky.convo.defs.logLockConvo, ev) ||
bsky.isType(chat.bsky.convo.defs.logUnlockConvo, ev) ||
bsky.isType(chat.bsky.convo.defs.logLockConvoPermanently, ev) ||
bsky.isType(chat.bsky.convo.defs.logEditGroup, ev) ||
bsky.isType(chat.bsky.convo.defs.logCreateJoinLink, ev) ||
bsky.isType(chat.bsky.convo.defs.logEditJoinLink, ev) ||
bsky.isType(chat.bsky.convo.defs.logEnableJoinLink, ev) ||
bsky.isType(chat.bsky.convo.defs.logDisableJoinLink, ev)
if (!isSystem) return null
return ev.message
}
@@ -89,8 +82,8 @@ function toSystemMessageView(
* the fields the deleted view carries so a reply can render it as deleted.
*/
function toDeletedMessageView(
m: ChatBskyConvoDefs.MessageView,
): $Typed<ChatBskyConvoDefs.DeletedMessageView> {
m: chat.bsky.convo.defs.MessageView,
): $Typed<chat.bsky.convo.defs.DeletedMessageView> {
return {
$type: 'chat.bsky.convo.defs#deletedMessageView',
id: m.id,
@@ -105,7 +98,7 @@ export class Convo {
private chatClient: Client
private events: MessagesEventBus
private senderUserDid: string
private senderUserDid: DidString
private status: ConvoStatus = ConvoStatus.Uninitialized
private error: ConvoError | undefined
@@ -115,15 +108,15 @@ export class Convo {
private pastMessages: Map<
string,
| ChatBskyConvoDefs.MessageView
| ChatBskyConvoDefs.DeletedMessageView
| ChatBskyConvoDefs.SystemMessageView
| chat.bsky.convo.defs.MessageView
| chat.bsky.convo.defs.DeletedMessageView
| chat.bsky.convo.defs.SystemMessageView
> = new Map()
private newMessages: Map<
string,
| ChatBskyConvoDefs.MessageView
| ChatBskyConvoDefs.DeletedMessageView
| ChatBskyConvoDefs.SystemMessageView
| chat.bsky.convo.defs.MessageView
| chat.bsky.convo.defs.DeletedMessageView
| chat.bsky.convo.defs.SystemMessageView
> = new Map()
private pendingMessages: Map<
string,
@@ -131,13 +124,13 @@ export class Convo {
id: string
message: chat.bsky.convo.defs.MessageInput
optimisticEmbedView?:
| $Typed<AppBskyEmbedRecord.View>
| $Typed<ChatBskyEmbedJoinLink.View>
optimisticReplyTo?: $Typed<ChatBskyConvoDefs.MessageView>
| $Typed<app.bsky.embed.record.View>
| $Typed<chat.bsky.embed.joinLink.View>
optimisticReplyTo?: $Typed<chat.bsky.convo.defs.MessageView>
}
> = new Map()
private deletedMessages: Set<string> = new Set()
private relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic> =
private relatedProfiles: Map<string, chat.bsky.actor.defs.ProfileViewBasic> =
new Map()
/**
* Accumulated profile shadow state, keyed by did. The profiles this agent
@@ -157,8 +150,8 @@ export class Convo {
convoId: string
convo: ConvoWithDetails | undefined
sender: ChatBskyActorDefs.ProfileViewBasic | undefined
recipients: ChatBskyActorDefs.ProfileViewBasic[] | undefined
sender: chat.bsky.actor.defs.ProfileViewBasic | undefined
recipients: chat.bsky.actor.defs.ProfileViewBasic[] | undefined
snapshot: ConvoState | undefined
constructor(params: ConvoParams) {
@@ -596,7 +589,7 @@ export class Convo {
}
}
private setConvo(convo: ChatBskyConvoDefs.ConvoView) {
private setConvo(convo: chat.bsky.convo.defs.ConvoView) {
this.convo = parseConvoView(convo, this.senderUserDid) ?? this.convo
if (this.convo) {
for (const member of this.convo.members) {
@@ -606,7 +599,7 @@ export class Convo {
this.applyProfileShadows()
}
private updateConvo(convo: Partial<ChatBskyConvoDefs.ConvoView>) {
private updateConvo(convo: Partial<chat.bsky.convo.defs.ConvoView>) {
if (this.convo) {
this.convo =
parseConvoView({...this.convo.view, ...convo}, this.senderUserDid) ??
@@ -716,7 +709,7 @@ export class Convo {
}
private pendingFetchConvo:
| Promise<{convo: ChatBskyConvoDefs.ConvoView}>
| Promise<{convo: chat.bsky.convo.defs.ConvoView}>
| undefined
async fetchConvo() {
if (this.pendingFetchConvo) return this.pendingFetchConvo
@@ -836,9 +829,9 @@ export class Convo {
for (const message of messages) {
if (
ChatBskyConvoDefs.isMessageView(message) ||
ChatBskyConvoDefs.isDeletedMessageView(message) ||
ChatBskyConvoDefs.isSystemMessageView(message)
bsky.isType(chat.bsky.convo.defs.messageView, message) ||
bsky.isType(chat.bsky.convo.defs.deletedMessageView, message) ||
bsky.isType(chat.bsky.convo.defs.systemMessageView, message)
) {
/*
* If this message is already in new messages, it was added by the
@@ -913,7 +906,7 @@ export class Convo {
this.commit()
}
ingestFirehose(events: ChatBskyConvoGetLog.OutputSchema['logs']) {
ingestFirehose(events: chat.bsky.convo.getLog.$OutputBody['logs']) {
let needsCommit = false
for (const ev of events) {
@@ -950,8 +943,8 @@ export class Convo {
}
if (
ChatBskyConvoDefs.isLogCreateMessage(ev) &&
ChatBskyConvoDefs.isMessageView(ev.message)
bsky.isType(chat.bsky.convo.defs.logCreateMessage, ev) &&
bsky.isType(chat.bsky.convo.defs.messageView, ev.message)
) {
/*
* If this message is already in past messages, the initial
@@ -976,8 +969,8 @@ export class Convo {
}
needsCommit = true
} else if (
ChatBskyConvoDefs.isLogDeleteMessage(ev) &&
ChatBskyConvoDefs.isDeletedMessageView(ev.message)
bsky.isType(chat.bsky.convo.defs.logDeleteMessage, ev) &&
bsky.isType(chat.bsky.convo.defs.deletedMessageView, ev.message)
) {
/*
* Remove the message itself, and keep its id in `deletedMessages`
@@ -992,9 +985,9 @@ export class Convo {
this.deletedMessages.add(ev.message.id)
needsCommit = true
} else if (
(ChatBskyConvoDefs.isLogAddReaction(ev) ||
ChatBskyConvoDefs.isLogRemoveReaction(ev)) &&
ChatBskyConvoDefs.isMessageView(ev.message)
(bsky.isType(chat.bsky.convo.defs.logAddReaction, ev) ||
bsky.isType(chat.bsky.convo.defs.logRemoveReaction, ev)) &&
bsky.isType(chat.bsky.convo.defs.messageView, ev.message)
) {
/*
* Update if we have this in state - replace message wholesale. If we don't, don't worry about it.
@@ -1033,9 +1026,9 @@ export class Convo {
sendMessage(
message: chat.bsky.convo.defs.MessageInput,
optimisticEmbedView?:
| $Typed<AppBskyEmbedRecord.View>
| $Typed<ChatBskyEmbedJoinLink.View>,
optimisticReplyTo?: $Typed<ChatBskyConvoDefs.MessageView>,
| $Typed<app.bsky.embed.record.View>
| $Typed<chat.bsky.embed.joinLink.View>,
optimisticReplyTo?: $Typed<chat.bsky.convo.defs.MessageView>,
) {
// Ignore empty messages for now since they have no other purpose atm
if (!message.text.trim() && !message.embed) return
@@ -1110,7 +1103,7 @@ export class Convo {
this.commit()
}
updateJoinLink(joinLink: ChatBskyGroupDefs.JoinLinkView | undefined) {
updateJoinLink(joinLink: chat.bsky.group.defs.JoinLinkView | undefined) {
if (this.convo?.kind !== 'group') {
throw new Error('updateJoinLink can only be called on group convo')
}
@@ -1126,7 +1119,7 @@ export class Convo {
}
updateLockStatus(
lockStatus: ChatBskyConvoDefs.ConvoLockStatus,
lockStatus: chat.bsky.convo.defs.ConvoLockStatus,
lockStatusModerationOverride: boolean,
) {
if (this.convo?.kind !== 'group') {
@@ -1194,8 +1187,8 @@ export class Convo {
}
/*
* The lex client throws `XrpcResponseError`, not `@atproto/api`'s
* `XRPCError`, so the status/message branch narrows on the lex class. Only
* The lex client throws `XrpcResponseError`, so the status/message branch
* narrows on that class. Only
* a genuine server response carries a status: transport and internal lex
* failures are `XrpcInternalError`s and fall through to the generic arm,
* where `isNetworkError` keeps them out of the logs.
@@ -1340,11 +1333,11 @@ export class Convo {
* matching what the server returns on refresh.
*/
private tombstoneDeletedReplyTo(
m: ChatBskyConvoDefs.MessageView,
): ChatBskyConvoDefs.MessageView {
m: chat.bsky.convo.defs.MessageView,
): chat.bsky.convo.defs.MessageView {
const {replyTo} = m
if (
!ChatBskyConvoDefs.isMessageView(replyTo) ||
!bsky.isType(chat.bsky.convo.defs.messageView, replyTo) ||
!this.deletedMessages.has(replyTo.id)
) {
return m
@@ -1359,19 +1352,19 @@ export class Convo {
const items: ConvoItem[] = []
this.pastMessages.forEach(m => {
if (ChatBskyConvoDefs.isMessageView(m)) {
if (bsky.isType(chat.bsky.convo.defs.messageView, m)) {
items.unshift({
type: 'message',
key: m.id,
message: this.tombstoneDeletedReplyTo(m),
})
} else if (ChatBskyConvoDefs.isDeletedMessageView(m)) {
} else if (bsky.isType(chat.bsky.convo.defs.deletedMessageView, m)) {
items.unshift({
type: 'deleted-message',
key: m.id,
message: m,
})
} else if (ChatBskyConvoDefs.isSystemMessageView(m)) {
} else if (bsky.isType(chat.bsky.convo.defs.systemMessageView, m)) {
items.unshift({
type: 'system-message',
key: m.id,
@@ -1392,19 +1385,19 @@ export class Convo {
}
this.newMessages.forEach(m => {
if (ChatBskyConvoDefs.isMessageView(m)) {
if (bsky.isType(chat.bsky.convo.defs.messageView, m)) {
items.push({
type: 'message',
key: m.id,
message: this.tombstoneDeletedReplyTo(m),
})
} else if (ChatBskyConvoDefs.isDeletedMessageView(m)) {
} else if (bsky.isType(chat.bsky.convo.defs.deletedMessageView, m)) {
items.push({
type: 'deleted-message',
key: m.id,
message: m,
})
} else if (ChatBskyConvoDefs.isSystemMessageView(m)) {
} else if (bsky.isType(chat.bsky.convo.defs.systemMessageView, m)) {
items.push({
type: 'system-message',
key: m.id,
@@ -1428,7 +1421,7 @@ export class Convo {
$type: 'chat.bsky.convo.defs#messageView',
id: nanoid(),
rev: '__fake__',
sentAt: new Date().toISOString(),
sentAt: toDatetimeString(new Date()),
sender: {
$type: 'chat.bsky.convo.defs#messageViewSender',
did: this.senderUserDid,
@@ -1470,16 +1463,16 @@ export class Convo {
* @param emoji - must be one grapheme
*/
async addReaction(messageId: string, emoji: string) {
const optimisticReaction = {
const optimisticReaction: chat.bsky.convo.defs.ReactionView = {
value: emoji,
sender: {did: this.senderUserDid},
createdAt: new Date().toISOString(),
createdAt: toDatetimeString(new Date()),
}
let restore: null | (() => void) = null
if (this.pastMessages.has(messageId)) {
const prevMessage = this.pastMessages.get(messageId)
if (
ChatBskyConvoDefs.isMessageView(prevMessage) &&
bsky.isType(chat.bsky.convo.defs.messageView, prevMessage) &&
// skip optimistic update if reaction already exists
!prevMessage.reactions?.find(
reaction =>
@@ -1509,7 +1502,7 @@ export class Convo {
} else if (this.newMessages.has(messageId)) {
const prevMessage = this.newMessages.get(messageId)
if (
ChatBskyConvoDefs.isMessageView(prevMessage) &&
bsky.isType(chat.bsky.convo.defs.messageView, prevMessage) &&
!prevMessage.reactions?.find(reaction => reaction.value === emoji)
) {
if (prevMessage.reactions && prevMessage.reactions.length >= 5)
@@ -1533,7 +1526,7 @@ export class Convo {
value: emoji,
convoId: this.convoId,
})
if (ChatBskyConvoDefs.isMessageView(data.message)) {
if (bsky.isType(chat.bsky.convo.defs.messageView, data.message)) {
if (this.pastMessages.has(messageId)) {
this.pastMessages.set(messageId, data.message)
this.commit()
@@ -1558,7 +1551,7 @@ export class Convo {
let restore: null | (() => void) = null
if (this.pastMessages.has(messageId)) {
const prevMessage = this.pastMessages.get(messageId)
if (ChatBskyConvoDefs.isMessageView(prevMessage)) {
if (bsky.isType(chat.bsky.convo.defs.messageView, prevMessage)) {
this.pastMessages.set(messageId, {
...prevMessage,
reactions: prevMessage.reactions?.filter(
@@ -1575,7 +1568,7 @@ export class Convo {
}
} else if (this.newMessages.has(messageId)) {
const prevMessage = this.newMessages.get(messageId)
if (ChatBskyConvoDefs.isMessageView(prevMessage)) {
if (bsky.isType(chat.bsky.convo.defs.messageView, prevMessage)) {
this.newMessages.set(messageId, {
...prevMessage,
reactions: prevMessage.reactions?.filter(
+11 -9
View File
@@ -6,7 +6,6 @@ import {
useState,
useSyncExternalStore,
} from 'react'
import {ChatBskyConvoDefs} from '@atproto/api'
import {useFocusEffect} from '@react-navigation/native'
import {useQueryClient} from '@tanstack/react-query'
@@ -30,12 +29,14 @@ import {RQKEY_ROOT as ListConvosQueryKeyRoot} from '#/state/queries/messages/lis
import {RQKEY as createProfileQueryKey} from '#/state/queries/profile'
import {useChatClient} from '#/state/session'
import {type GroupConvoMember} from '#/components/dms/util'
import {chat} from '#/lexicons'
import * as bsky from '#/types/bsky'
export * from '#/state/messages/convo/util'
function membersChanged(
a: ChatBskyConvoDefs.ConvoView['members'],
b: ChatBskyConvoDefs.ConvoView['members'],
a: chat.bsky.convo.defs.ConvoView['members'],
b: chat.bsky.convo.defs.ConvoView['members'],
) {
if (a.length !== b.length) return true
const aDids = new Set(a.map(m => m.did))
@@ -83,9 +84,10 @@ export function ConvoProvider({
const chatClient = useChatClient()
const events = useMessagesEventBus()
const [convo] = useState(() => {
const placeholder = queryClient.getQueryData<ChatBskyConvoDefs.ConvoView>(
getConvoKey(convoId),
)
const placeholder =
queryClient.getQueryData<chat.bsky.convo.defs.ConvoView>(
getConvoKey(convoId),
)
return new Convo({
convoId,
chatClient,
@@ -151,14 +153,14 @@ export function ConvoProvider({
const queryKey = event.query.queryKey as string[]
if (queryKey[0] === root && queryKey[1] === id) {
const data = event.query.state.data as
| ChatBskyConvoDefs.ConvoView
| chat.bsky.convo.defs.ConvoView
| undefined
if (data && convo.convo && data.muted !== convo.convo.view.muted) {
convo.updateMuted(data.muted)
}
if (
data &&
ChatBskyConvoDefs.isGroupConvo(data.kind) &&
bsky.isType(chat.bsky.convo.defs.groupConvo, data.kind) &&
convo.convo?.kind === 'group'
) {
if (data.kind.name !== convo.convo.details.name) {
@@ -180,7 +182,7 @@ export function ConvoProvider({
}
if (
data &&
ChatBskyConvoDefs.isGroupConvo(data.kind) &&
bsky.isType(chat.bsky.convo.defs.groupConvo, data.kind) &&
convo.convo?.kind === 'group' &&
(membersChanged(data.members, convo.convo.members) ||
data.kind.memberCount !== convo.convo.details.memberCount)
+14 -21
View File
@@ -1,15 +1,8 @@
import {
type $Typed,
type AppBskyEmbedRecord,
type ChatBskyActorDefs,
type ChatBskyConvoDefs,
type ChatBskyEmbedJoinLink,
} from '@atproto/api'
import {type Client} from '@atproto/lex'
import {type $Typed, type Client} from '@atproto/lex'
import {type MessagesEventBus} from '#/state/messages/events/agent'
import {type ConvoWithDetails} from '#/components/dms/util'
import {type chat} from '#/lexicons'
import {type app, type chat} from '#/lexicons'
export type ConvoParams = {
convoId: string
@@ -17,7 +10,7 @@ export type ConvoParams = {
chatClient: Client
events: MessagesEventBus
placeholderData?: {
convo: ChatBskyConvoDefs.ConvoView
convo: chat.bsky.convo.defs.ConvoView
}
}
@@ -75,12 +68,12 @@ export type ConvoItem =
| {
type: 'message'
key: string
message: ChatBskyConvoDefs.MessageView
message: chat.bsky.convo.defs.MessageView
}
| {
type: 'pending-message'
key: string
message: ChatBskyConvoDefs.MessageView
message: chat.bsky.convo.defs.MessageView
failed: boolean
/**
* Retry sending the message. If present, the message is in a failed state.
@@ -90,12 +83,12 @@ export type ConvoItem =
| {
type: 'deleted-message'
key: string
message: ChatBskyConvoDefs.DeletedMessageView
message: chat.bsky.convo.defs.DeletedMessageView
}
| {
type: 'system-message'
key: string
message: ChatBskyConvoDefs.SystemMessageView
message: chat.bsky.convo.defs.SystemMessageView
}
| {
type: 'error'
@@ -111,10 +104,10 @@ type DeleteMessage = (messageId: string) => Promise<void>
type SendMessage = (
message: chat.bsky.convo.defs.MessageInput,
optimisticEmbedView:
| $Typed<AppBskyEmbedRecord.View>
| $Typed<ChatBskyEmbedJoinLink.View>
| $Typed<app.bsky.embed.record.View>
| $Typed<chat.bsky.embed.joinLink.View>
| undefined,
optimisticReplyTo?: $Typed<ChatBskyConvoDefs.MessageView>,
optimisticReplyTo?: $Typed<chat.bsky.convo.defs.MessageView>,
) => void
type FetchMessageHistory = () => Promise<void>
type MarkConvoAccepted = () => void
@@ -153,7 +146,7 @@ export type ConvoStateReady = {
status: ConvoStatus.Ready
items: ConvoItem[]
convo: ConvoWithDetails
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>
relatedProfiles: Map<string, chat.bsky.actor.defs.ProfileViewBasic>
error: undefined
isFetchingHistory: boolean
hasAllHistory: boolean
@@ -168,7 +161,7 @@ export type ConvoStateBackgrounded = {
status: ConvoStatus.Backgrounded
items: ConvoItem[]
convo: ConvoWithDetails
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>
relatedProfiles: Map<string, chat.bsky.actor.defs.ProfileViewBasic>
error: undefined
isFetchingHistory: boolean
hasAllHistory: boolean
@@ -183,7 +176,7 @@ export type ConvoStateSuspended = {
status: ConvoStatus.Suspended
items: ConvoItem[]
convo: ConvoWithDetails
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>
relatedProfiles: Map<string, chat.bsky.actor.defs.ProfileViewBasic>
error: undefined
isFetchingHistory: boolean
hasAllHistory: boolean
@@ -212,7 +205,7 @@ export type ConvoStateDisabled = {
status: ConvoStatus.Disabled
items: ConvoItem[]
convo: ConvoWithDetails
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>
relatedProfiles: Map<string, chat.bsky.actor.defs.ProfileViewBasic>
error: undefined
isFetchingHistory: boolean
hasAllHistory: boolean