@atproto/api@next integration (#7344)
* Bump SDK * Use consistent type in profile query * Omit from constraint for profile shadow * Replace isRecord with isValidRecord in QuoteEmbed * Omit type from constraint for old ProfileCard * Omit type from constraint in profile queries where appropriate * Use correct type for update profile mutation * Conslidate and fix check for isValidRecord in Post.tsx * Replace isRecord with isValidRecord in PostThreadItem * Remove redundant cast in PostThreadFollowBtn * Ignore errors in DebugMod screen * Use matching type in ProfileFollows screen * Use matching type in ProfileFollowers screen * Migrate to isValidRecord in PostFeedItem * Use matching type if PostRepostedBy * Omit type from constraint in avatar props * Use matching types in NotificationFeedItem * Todo * Use isValidRecord in NotfyFeedItem * Improve MediaPreview types * Migrate another isValidRecord in NotificationFeedItem * Migrate to isValidView in queries/util * Migrate to isValidRecord in threadgate/util * Fix types in threadgates * Fix up types in starter-packs queries * Todo * Specify exact types in search-posts * Use internal type util to align types * Ditto last * Migrate postgate/index * Specify exact types in post-thread * Use correct type in post-quotes * FIX potential bug in post-thread * Use correct type in post-feed * Add correct type guards to notifications/feed * Migrate a guard in notifications/util * Migrate guard in Wizard/State * [@next] Profile handling, migrate `ProfileCard` (#7347) * Introduce new utils for profiles, migrate old ProfileCard * Rename, reorg * Add parseEmbed utils * Expand AnyProfileView to include chat profile view, update post shadow to reflect this * Cast for perf reasons * Tighten up types now that we have AnyProfileView * Add fastIsType util * Use `assertDid` Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com> * Use util types * Comment * Use fastIsType where no validation was happening before * suggestions (#7382) * suggestions * Revert unneeded changes --------- Co-authored-by: Eric Bailey <git@esb.lol> * Use new util * Rename to dangerousIsType * Convert object shape * Use dangerous util * Use dangerous util * Use dangerous util, we can trust post records * Use dangerous util * Use AnyProfileVIew * Convert object shape * Clean up handling * Patch moderateProfile to accept known profile views, to discuss * Add AnyStarterPackView and related, implement in first usage * Remove validation, fix type, fix ref * Migrate over list-conversations * Clarify intent behind precacheProfile and its unstable query cache * Clean up unstable profile cache * Fix types during label creation in PwiOptOut (#7346) * Tighten types in queries/list * Chat: use correct profile views * Chat: fix log type check * Chat: construct lexically correct shape, even though it's only internal usage * Chat: use correct profile types * Chat: fix type check in logs * Starter: use correct profile types * Starter: use correct profile types * Starter: tighten types to match lex * Any profile type will work in blocked-and-muted * Use dangerous util * Use dangerousIsType * Update new ProfileCard to use AnyProfileView * Use dangerousIsType * Remove outdated todo * Use correct profile type * Use correct profile types * Tighten up types * Use dangerousIsType * Chat: more type fixes * Remove unused file * Add a few utils * Remove unused file * Ignore feedPost.__source * Clean up types, leave validation in critical path * Use dangerousIstype * Use ANyProfileView * Use isValidRecord * Use dangerousIsType * Fix types in ListCard * Fix FeedInterstitials types * Fix types in FeedCard * Fix types in dms ReportDialog * Fix types in SearchablePeopleList * Fix bad type in composer opts * Starter: ok these need to be loose too * Clarify docs Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com> * Less code Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com> * Use package exports Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com> * Use package exports * Bump sdk, update $Typed imports * Format * Format * Fix weird TS error * Remove patch * Beter name * It's memo, can validate * Tighten up parseEmbed, dogfood * Bump sdk * Use asPredicate * Loosen types a bit * use asPredicate * Fix types * Use asPredicate * Use asPredicate * Use asPredicate * Clean up upsertProfile types * Use asPredicate * Use Un util * Fix types * Use new AnyProfileView * Use dangerousIsType * Use asPredicate * Use asPredicate * Add fallback content-type to pass typecheck * Clean up upsertProfile types * Align types * Use dangerousIsType * Use dangerousIsType * Use asPredicate * Align types * Convert findLast * Align types * Just ignore type errors and use findLast * Rename atproto -> bsky * Add validate util * Fix type error * Loosen types * Export post * rename atp bsky * Remove unused code * minor changes * Bump deps * Fix types * Tighten back up loose check * Tighten back up loose check * Fix small bug * Update comment * Revert change --------- Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com> Co-authored-by: Matthieu Sieben <matthieu.sieben@gmail.com>
This commit is contained in:
Vendored
+7
-6
@@ -1,9 +1,9 @@
|
||||
import {useEffect, useMemo, useState} from 'react'
|
||||
import {AppBskyActorDefs} from '@atproto/api'
|
||||
import {QueryClient} from '@tanstack/react-query'
|
||||
import EventEmitter from 'eventemitter3'
|
||||
|
||||
import {batchedUpdates} from '#/lib/batchedUpdates'
|
||||
import * as bsky from '#/types/bsky'
|
||||
import {findAllProfilesInQueryData as findAllProfilesInActorSearchQueryData} from '../queries/actor-search'
|
||||
import {findAllProfilesInQueryData as findAllProfilesInKnownFollowersQueryData} from '../queries/known-followers'
|
||||
import {findAllProfilesInQueryData as findAllProfilesInListMembersQueryData} from '../queries/list-members'
|
||||
@@ -20,6 +20,7 @@ import {findAllProfilesInQueryData as findAllProfilesInProfileFollowersQueryData
|
||||
import {findAllProfilesInQueryData as findAllProfilesInProfileFollowsQueryData} from '../queries/profile-follows'
|
||||
import {findAllProfilesInQueryData as findAllProfilesInSuggestedFollowsQueryData} from '../queries/suggested-follows'
|
||||
import {castAsShadow, Shadow} from './types'
|
||||
|
||||
export type {Shadow} from './types'
|
||||
|
||||
export interface ProfileShadow {
|
||||
@@ -29,13 +30,13 @@ export interface ProfileShadow {
|
||||
}
|
||||
|
||||
const shadows: WeakMap<
|
||||
AppBskyActorDefs.ProfileView,
|
||||
bsky.profile.AnyProfileView,
|
||||
Partial<ProfileShadow>
|
||||
> = new WeakMap()
|
||||
const emitter = new EventEmitter()
|
||||
|
||||
export function useProfileShadow<
|
||||
TProfileView extends AppBskyActorDefs.ProfileView,
|
||||
TProfileView extends bsky.profile.AnyProfileView,
|
||||
>(profile: TProfileView): Shadow<TProfileView> {
|
||||
const [shadow, setShadow] = useState(() => shadows.get(profile))
|
||||
const [prevPost, setPrevPost] = useState(profile)
|
||||
@@ -68,7 +69,7 @@ export function useProfileShadow<
|
||||
* This is useful for when the profile is not guaranteed to be loaded yet.
|
||||
*/
|
||||
export function useMaybeProfileShadow<
|
||||
TProfileView extends AppBskyActorDefs.ProfileView,
|
||||
TProfileView extends bsky.profile.AnyProfileView,
|
||||
>(profile?: TProfileView): Shadow<TProfileView> | undefined {
|
||||
const [shadow, setShadow] = useState(() =>
|
||||
profile ? shadows.get(profile) : undefined,
|
||||
@@ -115,7 +116,7 @@ export function updateProfileShadow(
|
||||
})
|
||||
}
|
||||
|
||||
function mergeShadow<TProfileView extends AppBskyActorDefs.ProfileView>(
|
||||
function mergeShadow<TProfileView extends bsky.profile.AnyProfileView>(
|
||||
profile: TProfileView,
|
||||
shadow: Partial<ProfileShadow>,
|
||||
): Shadow<TProfileView> {
|
||||
@@ -137,7 +138,7 @@ function mergeShadow<TProfileView extends AppBskyActorDefs.ProfileView>(
|
||||
function* findProfilesInCache(
|
||||
queryClient: QueryClient,
|
||||
did: string,
|
||||
): Generator<AppBskyActorDefs.ProfileView, void> {
|
||||
): Generator<bsky.profile.AnyProfileView, void> {
|
||||
yield* findAllProfilesInListMembersQueryData(queryClient, did)
|
||||
yield* findAllProfilesInMyBlockedAccountsQueryData(queryClient, did)
|
||||
yield* findAllProfilesInMyMutedAccountsQueryData(queryClient, did)
|
||||
|
||||
Vendored
+1
@@ -69,6 +69,7 @@ function useMigrateMutes(setThreadMute: SetStateContext) {
|
||||
while (!cancelled) {
|
||||
const threads = persisted.get('mutedThreads')
|
||||
|
||||
// @ts-ignore findLast is polyfilled - esb
|
||||
const root = threads.findLast(uri => uri.includes(currentAccount.did))
|
||||
|
||||
if (!root) break
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {
|
||||
AppBskyActorDefs,
|
||||
BskyAgent,
|
||||
ChatBskyActorDefs,
|
||||
ChatBskyConvoDefs,
|
||||
ChatBskyConvoGetLog,
|
||||
ChatBskyConvoSendMessage,
|
||||
@@ -80,8 +80,8 @@ export class Convo {
|
||||
|
||||
convoId: string
|
||||
convo: ChatBskyConvoDefs.ConvoView | undefined
|
||||
sender: AppBskyActorDefs.ProfileViewBasic | undefined
|
||||
recipients: AppBskyActorDefs.ProfileViewBasic[] | undefined
|
||||
sender: ChatBskyActorDefs.ProfileViewBasic | undefined
|
||||
recipients: ChatBskyActorDefs.ProfileViewBasic[] | undefined
|
||||
snapshot: ConvoState | undefined
|
||||
|
||||
constructor(params: ConvoParams) {
|
||||
@@ -463,7 +463,7 @@ export class Convo {
|
||||
throw new Error('Convo: could not find recipients in convo')
|
||||
}
|
||||
|
||||
const userIsDisabled = this.sender.chatDisabled as boolean
|
||||
const userIsDisabled = Boolean(this.sender.chatDisabled)
|
||||
|
||||
if (userIsDisabled) {
|
||||
this.dispatch({event: ConvoDispatchEvent.Disable})
|
||||
@@ -529,8 +529,8 @@ export class Convo {
|
||||
private pendingFetchConvo:
|
||||
| Promise<{
|
||||
convo: ChatBskyConvoDefs.ConvoView
|
||||
sender: AppBskyActorDefs.ProfileViewBasic | undefined
|
||||
recipients: AppBskyActorDefs.ProfileViewBasic[]
|
||||
sender: ChatBskyActorDefs.ProfileViewBasic | undefined
|
||||
recipients: ChatBskyActorDefs.ProfileViewBasic[]
|
||||
}>
|
||||
| undefined
|
||||
async fetchConvo() {
|
||||
@@ -538,8 +538,8 @@ export class Convo {
|
||||
|
||||
this.pendingFetchConvo = new Promise<{
|
||||
convo: ChatBskyConvoDefs.ConvoView
|
||||
sender: AppBskyActorDefs.ProfileViewBasic | undefined
|
||||
recipients: AppBskyActorDefs.ProfileViewBasic[]
|
||||
sender: ChatBskyActorDefs.ProfileViewBasic | undefined
|
||||
recipients: ChatBskyActorDefs.ProfileViewBasic[]
|
||||
}>(async (resolve, reject) => {
|
||||
try {
|
||||
const response = await networkRetry(2, () => {
|
||||
@@ -704,7 +704,7 @@ export class Convo {
|
||||
* If there's a rev, we should handle it. If there's not a rev, we don't
|
||||
* know what it is.
|
||||
*/
|
||||
if (typeof ev.rev === 'string') {
|
||||
if ('rev' in ev && typeof ev.rev === 'string') {
|
||||
const isUninitialized = !this.latestRev
|
||||
const isNewEvent = this.latestRev && ev.rev > this.latestRev
|
||||
|
||||
@@ -1049,7 +1049,10 @@ export class Convo {
|
||||
* `getItems` is only run in "active" status states, where
|
||||
* `this.sender` is defined
|
||||
*/
|
||||
sender: this.sender!,
|
||||
sender: {
|
||||
$type: 'chat.bsky.convo.defs#messageViewSender',
|
||||
did: this.sender!.did,
|
||||
},
|
||||
},
|
||||
nextMessage: null,
|
||||
prevMessage: null,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {
|
||||
AppBskyActorDefs,
|
||||
BskyAgent,
|
||||
ChatBskyActorDefs,
|
||||
ChatBskyConvoDefs,
|
||||
ChatBskyConvoSendMessage,
|
||||
} from '@atproto/api'
|
||||
@@ -147,8 +147,8 @@ export type ConvoStateUninitialized = {
|
||||
items: []
|
||||
convo: ChatBskyConvoDefs.ConvoView | undefined
|
||||
error: undefined
|
||||
sender: AppBskyActorDefs.ProfileViewBasic | undefined
|
||||
recipients: AppBskyActorDefs.ProfileViewBasic[] | undefined
|
||||
sender: ChatBskyActorDefs.ProfileViewBasic | undefined
|
||||
recipients: ChatBskyActorDefs.ProfileViewBasic[] | undefined
|
||||
isFetchingHistory: false
|
||||
deleteMessage: undefined
|
||||
sendMessage: undefined
|
||||
@@ -159,8 +159,8 @@ export type ConvoStateInitializing = {
|
||||
items: []
|
||||
convo: ChatBskyConvoDefs.ConvoView | undefined
|
||||
error: undefined
|
||||
sender: AppBskyActorDefs.ProfileViewBasic | undefined
|
||||
recipients: AppBskyActorDefs.ProfileViewBasic[] | undefined
|
||||
sender: ChatBskyActorDefs.ProfileViewBasic | undefined
|
||||
recipients: ChatBskyActorDefs.ProfileViewBasic[] | undefined
|
||||
isFetchingHistory: boolean
|
||||
deleteMessage: undefined
|
||||
sendMessage: undefined
|
||||
@@ -171,8 +171,8 @@ export type ConvoStateReady = {
|
||||
items: ConvoItem[]
|
||||
convo: ChatBskyConvoDefs.ConvoView
|
||||
error: undefined
|
||||
sender: AppBskyActorDefs.ProfileViewBasic
|
||||
recipients: AppBskyActorDefs.ProfileViewBasic[]
|
||||
sender: ChatBskyActorDefs.ProfileViewBasic
|
||||
recipients: ChatBskyActorDefs.ProfileViewBasic[]
|
||||
isFetchingHistory: boolean
|
||||
deleteMessage: DeleteMessage
|
||||
sendMessage: SendMessage
|
||||
@@ -183,8 +183,8 @@ export type ConvoStateBackgrounded = {
|
||||
items: ConvoItem[]
|
||||
convo: ChatBskyConvoDefs.ConvoView
|
||||
error: undefined
|
||||
sender: AppBskyActorDefs.ProfileViewBasic
|
||||
recipients: AppBskyActorDefs.ProfileViewBasic[]
|
||||
sender: ChatBskyActorDefs.ProfileViewBasic
|
||||
recipients: ChatBskyActorDefs.ProfileViewBasic[]
|
||||
isFetchingHistory: boolean
|
||||
deleteMessage: DeleteMessage
|
||||
sendMessage: SendMessage
|
||||
@@ -195,8 +195,8 @@ export type ConvoStateSuspended = {
|
||||
items: ConvoItem[]
|
||||
convo: ChatBskyConvoDefs.ConvoView
|
||||
error: undefined
|
||||
sender: AppBskyActorDefs.ProfileViewBasic
|
||||
recipients: AppBskyActorDefs.ProfileViewBasic[]
|
||||
sender: ChatBskyActorDefs.ProfileViewBasic
|
||||
recipients: ChatBskyActorDefs.ProfileViewBasic[]
|
||||
isFetchingHistory: boolean
|
||||
deleteMessage: DeleteMessage
|
||||
sendMessage: SendMessage
|
||||
@@ -219,8 +219,8 @@ export type ConvoStateDisabled = {
|
||||
items: ConvoItem[]
|
||||
convo: ChatBskyConvoDefs.ConvoView
|
||||
error: undefined
|
||||
sender: AppBskyActorDefs.ProfileViewBasic
|
||||
recipients: AppBskyActorDefs.ProfileViewBasic[]
|
||||
sender: ChatBskyActorDefs.ProfileViewBasic
|
||||
recipients: ChatBskyActorDefs.ProfileViewBasic[]
|
||||
isFetchingHistory: boolean
|
||||
deleteMessage: DeleteMessage
|
||||
sendMessage: SendMessage
|
||||
|
||||
@@ -65,10 +65,7 @@ export class MessagesEventBus {
|
||||
const handle = (event: MessagesEventBusEvent) => {
|
||||
if (event.type === 'logs' && options.convoId) {
|
||||
const filteredLogs = event.logs.filter(log => {
|
||||
if (
|
||||
typeof log.convoId === 'string' &&
|
||||
log.convoId === options.convoId
|
||||
) {
|
||||
if ('convoId' in log && log.convoId === options.convoId) {
|
||||
return log.convoId === options.convoId
|
||||
}
|
||||
return false
|
||||
@@ -355,7 +352,7 @@ export class MessagesEventBus {
|
||||
* If there's a rev, we should handle it. If there's not a rev, we don't
|
||||
* know what it is.
|
||||
*/
|
||||
if (typeof ev.rev === 'string') {
|
||||
if ('rev' in ev && typeof ev.rev === 'string') {
|
||||
/*
|
||||
* We only care about new events
|
||||
*/
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import {Image as RNImage} from 'react-native-image-crop-picker'
|
||||
import {
|
||||
$Typed,
|
||||
AppBskyGraphDefs,
|
||||
AppBskyGraphGetList,
|
||||
AppBskyGraphList,
|
||||
AtUri,
|
||||
BskyAgent,
|
||||
ComAtprotoRepoApplyWrites,
|
||||
Facet,
|
||||
Un$Typed,
|
||||
} from '@atproto/api'
|
||||
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
||||
import chunk from 'lodash.chunk'
|
||||
@@ -68,7 +71,7 @@ export function useListCreateMutation() {
|
||||
) {
|
||||
throw new Error('Invalid list purpose: must be curatelist or modlist')
|
||||
}
|
||||
const record: AppBskyGraphList.Record = {
|
||||
const record: Un$Typed<AppBskyGraphList.Record> = {
|
||||
purpose,
|
||||
name,
|
||||
description,
|
||||
@@ -212,7 +215,9 @@ export function useListDeleteMutation() {
|
||||
}
|
||||
|
||||
// batch delete the list and listitem records
|
||||
const createDel = (uri: string) => {
|
||||
const createDel = (
|
||||
uri: string,
|
||||
): $Typed<ComAtprotoRepoApplyWrites.Delete> => {
|
||||
const urip = new AtUri(uri)
|
||||
return {
|
||||
$type: 'com.atproto.repo.applyWrites#delete',
|
||||
|
||||
@@ -69,12 +69,10 @@ export function useDeleteActorDeclaration() {
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
if (!currentAccount) throw new Error('Not signed in')
|
||||
// TODO(sam): remove validate: false once PDSes have the new lexicon
|
||||
const result = await agent.api.com.atproto.repo.deleteRecord({
|
||||
repo: currentAccount.did,
|
||||
collection: 'chat.bsky.actor.declaration',
|
||||
rkey: 'self',
|
||||
validate: false,
|
||||
})
|
||||
return result
|
||||
},
|
||||
|
||||
@@ -101,7 +101,7 @@ export function ListConvosProviderInner({
|
||||
events => {
|
||||
if (events.type !== 'logs') return
|
||||
|
||||
events.logs.forEach(log => {
|
||||
for (const log of events.logs) {
|
||||
if (ChatBskyConvoDefs.isLogBeginConvo(log)) {
|
||||
debouncedRefetch()
|
||||
} else if (ChatBskyConvoDefs.isLogLeaveConvo(log)) {
|
||||
@@ -110,30 +110,40 @@ export function ListConvosProviderInner({
|
||||
)
|
||||
} else if (ChatBskyConvoDefs.isLogDeleteMessage(log)) {
|
||||
queryClient.setQueryData(RQKEY, (old: ConvoListQueryData) =>
|
||||
optimisticUpdate(log.convoId, old, convo =>
|
||||
log.message.id === convo.lastMessage?.id
|
||||
? {
|
||||
...convo,
|
||||
rev: log.rev,
|
||||
lastMessage: log.message,
|
||||
}
|
||||
: convo,
|
||||
),
|
||||
optimisticUpdate(log.convoId, old, convo => {
|
||||
if (
|
||||
(ChatBskyConvoDefs.isDeletedMessageView(log.message) ||
|
||||
ChatBskyConvoDefs.isMessageView(log.message)) &&
|
||||
(ChatBskyConvoDefs.isDeletedMessageView(convo.lastMessage) ||
|
||||
ChatBskyConvoDefs.isMessageView(convo.lastMessage))
|
||||
) {
|
||||
return log.message.id === convo.lastMessage.id
|
||||
? {
|
||||
...convo,
|
||||
rev: log.rev,
|
||||
lastMessage: log.message,
|
||||
}
|
||||
: convo
|
||||
} else {
|
||||
return convo
|
||||
}
|
||||
}),
|
||||
)
|
||||
} else if (ChatBskyConvoDefs.isLogCreateMessage(log)) {
|
||||
// Store in a new var to avoid TS errors due to closures.
|
||||
const logRef: ChatBskyConvoDefs.LogCreateMessage = log
|
||||
|
||||
queryClient.setQueryData(RQKEY, (old: ConvoListQueryData) => {
|
||||
if (!old) return old
|
||||
|
||||
function updateConvo(convo: ChatBskyConvoDefs.ConvoView) {
|
||||
if (!ChatBskyConvoDefs.isLogCreateMessage(log)) return convo
|
||||
|
||||
let unreadCount = convo.unreadCount
|
||||
if (convo.id !== currentConvoId) {
|
||||
if (
|
||||
ChatBskyConvoDefs.isMessageView(log.message) ||
|
||||
ChatBskyConvoDefs.isDeletedMessageView(log.message)
|
||||
ChatBskyConvoDefs.isMessageView(logRef.message) ||
|
||||
ChatBskyConvoDefs.isDeletedMessageView(logRef.message)
|
||||
) {
|
||||
if (log.message.sender.did !== currentAccount?.did) {
|
||||
if (logRef.message.sender.did !== currentAccount?.did) {
|
||||
unreadCount++
|
||||
}
|
||||
}
|
||||
@@ -143,8 +153,8 @@ export function ListConvosProviderInner({
|
||||
|
||||
return {
|
||||
...convo,
|
||||
rev: log.rev,
|
||||
lastMessage: log.message,
|
||||
rev: logRef.rev,
|
||||
lastMessage: logRef.message,
|
||||
unreadCount,
|
||||
}
|
||||
}
|
||||
@@ -152,10 +162,10 @@ export function ListConvosProviderInner({
|
||||
function filterConvoFromPage(
|
||||
convo: ChatBskyConvoDefs.ConvoView[],
|
||||
) {
|
||||
return convo.filter(c => c.id !== log.convoId)
|
||||
return convo.filter(c => c.id !== logRef.convoId)
|
||||
}
|
||||
|
||||
const existingConvo = getConvoFromQueryData(log.convoId, old)
|
||||
const existingConvo = getConvoFromQueryData(logRef.convoId, old)
|
||||
|
||||
if (existingConvo) {
|
||||
return {
|
||||
@@ -186,7 +196,7 @@ export function ListConvosProviderInner({
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
// get events for all chats
|
||||
|
||||
@@ -295,9 +295,11 @@ export function* findAllPostsInQueryData(
|
||||
}
|
||||
}
|
||||
|
||||
const quotedPost = getEmbeddedPost(item.subject?.embed)
|
||||
if (quotedPost && didOrHandleUriMatches(atUri, quotedPost)) {
|
||||
yield embedViewRecordToPostView(quotedPost!)
|
||||
if (AppBskyFeedDefs.isPostView(item.subject)) {
|
||||
const quotedPost = getEmbeddedPost(item.subject?.embed)
|
||||
if (quotedPost && didOrHandleUriMatches(atUri, quotedPost)) {
|
||||
yield embedViewRecordToPostView(quotedPost!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -307,7 +309,7 @@ export function* findAllPostsInQueryData(
|
||||
export function* findAllProfilesInQueryData(
|
||||
queryClient: QueryClient,
|
||||
did: string,
|
||||
): Generator<AppBskyActorDefs.ProfileView, void> {
|
||||
): Generator<AppBskyActorDefs.ProfileViewBasic, void> {
|
||||
const queryDatas = queryClient.getQueriesData<InfiniteData<FeedPage>>({
|
||||
queryKey: [RQKEY_ROOT],
|
||||
})
|
||||
@@ -323,9 +325,11 @@ export function* findAllProfilesInQueryData(
|
||||
) {
|
||||
yield item.subject.author
|
||||
}
|
||||
const quotedPost = getEmbeddedPost(item.subject?.embed)
|
||||
if (quotedPost?.author.did === did) {
|
||||
yield quotedPost.author
|
||||
if (AppBskyFeedDefs.isPostView(item.subject)) {
|
||||
const quotedPost = getEmbeddedPost(item.subject?.embed)
|
||||
if (quotedPost?.author.did === did) {
|
||||
yield quotedPost.author
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import {QueryClient} from '@tanstack/react-query'
|
||||
import chunk from 'lodash.chunk'
|
||||
|
||||
import {labelIsHideableOffense} from '#/lib/moderation'
|
||||
import * as bsky from '#/types/bsky'
|
||||
import {precacheProfile} from '../profile'
|
||||
import {FeedNotification, FeedPage, NotificationType} from './types'
|
||||
|
||||
@@ -205,12 +206,9 @@ async function fetchSubjects(
|
||||
),
|
||||
)
|
||||
const postsMap = new Map<string, AppBskyFeedDefs.PostView>()
|
||||
const packsMap = new Map<string, AppBskyGraphDefs.StarterPackView>()
|
||||
const packsMap = new Map<string, AppBskyGraphDefs.StarterPackViewBasic>()
|
||||
for (const post of postsChunks.flat()) {
|
||||
if (
|
||||
AppBskyFeedPost.isRecord(post.record) &&
|
||||
AppBskyFeedPost.validateRecord(post.record).success
|
||||
) {
|
||||
if (AppBskyFeedPost.isRecord(post.record)) {
|
||||
postsMap.set(post.uri, post)
|
||||
}
|
||||
}
|
||||
@@ -255,8 +253,14 @@ function getSubjectUri(
|
||||
return notif.uri
|
||||
} else if (type === 'post-like' || type === 'repost') {
|
||||
if (
|
||||
AppBskyFeedRepost.isRecord(notif.record) ||
|
||||
AppBskyFeedLike.isRecord(notif.record)
|
||||
bsky.dangerousIsType<AppBskyFeedRepost.Record>(
|
||||
notif.record,
|
||||
AppBskyFeedRepost.isRecord,
|
||||
) ||
|
||||
bsky.dangerousIsType<AppBskyFeedLike.Record>(
|
||||
notif.record,
|
||||
AppBskyFeedLike.isRecord,
|
||||
)
|
||||
) {
|
||||
return typeof notif.record.subject?.uri === 'string'
|
||||
? notif.record.subject?.uri
|
||||
|
||||
@@ -547,7 +547,7 @@ export function* findAllPostsInQueryData(
|
||||
export function* findAllProfilesInQueryData(
|
||||
queryClient: QueryClient,
|
||||
did: string,
|
||||
): Generator<AppBskyActorDefs.ProfileView, undefined> {
|
||||
): Generator<AppBskyActorDefs.ProfileViewBasic, undefined> {
|
||||
const queryDatas = queryClient.getQueriesData<
|
||||
InfiniteData<FeedPageUnselected>
|
||||
>({
|
||||
|
||||
@@ -70,7 +70,7 @@ export function usePostQuotesQuery(resolvedUri: string | undefined) {
|
||||
export function* findAllProfilesInQueryData(
|
||||
queryClient: QueryClient,
|
||||
did: string,
|
||||
): Generator<AppBskyActorDefs.ProfileView, void> {
|
||||
): Generator<AppBskyActorDefs.ProfileViewBasic, void> {
|
||||
const queryDatas = queryClient.getQueriesData<
|
||||
InfiniteData<AppBskyFeedGetQuotes.OutputSchema>
|
||||
>({
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
findAllProfilesInQueryData as findAllProfilesInSearchQueryData,
|
||||
} from '#/state/queries/search-posts'
|
||||
import {useAgent} from '#/state/session'
|
||||
import * as bsky from '#/types/bsky'
|
||||
import {
|
||||
findAllPostsInQueryData as findAllPostsInNotifsQueryData,
|
||||
findAllProfilesInQueryData as findAllProfilesInNotifsQueryData,
|
||||
@@ -332,8 +333,10 @@ function responseToThreadNodes(
|
||||
): ThreadNode {
|
||||
if (
|
||||
AppBskyFeedDefs.isThreadViewPost(node) &&
|
||||
AppBskyFeedPost.isRecord(node.post.record) &&
|
||||
AppBskyFeedPost.validateRecord(node.post.record).success
|
||||
bsky.dangerousIsType<AppBskyFeedPost.Record>(
|
||||
node.post.record,
|
||||
AppBskyFeedPost.isRecord,
|
||||
)
|
||||
) {
|
||||
const post = node.post
|
||||
// These should normally be present. They're missing only for
|
||||
@@ -364,7 +367,7 @@ function responseToThreadNodes(
|
||||
depth,
|
||||
isHighlightedPost: depth === 0,
|
||||
hasMore:
|
||||
direction === 'down' && !node.replies?.length && !!node.replyCount,
|
||||
direction === 'down' && !node.replies?.length && !!post.replyCount,
|
||||
isSelfThread: false, // populated `annotateSelfThread`
|
||||
hasMoreSelfThread: false, // populated in `annotateSelfThread`
|
||||
},
|
||||
@@ -497,7 +500,7 @@ export function* findAllPostsInQueryData(
|
||||
export function* findAllProfilesInQueryData(
|
||||
queryClient: QueryClient,
|
||||
did: string,
|
||||
): Generator<AppBskyActorDefs.ProfileView, void> {
|
||||
): Generator<AppBskyActorDefs.ProfileViewBasic, void> {
|
||||
const queryDatas = queryClient.getQueriesData<PostThreadQueryData>({
|
||||
queryKey: [RQKEY_ROOT],
|
||||
})
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
POSTGATE_COLLECTION,
|
||||
} from '#/state/queries/postgate/util'
|
||||
import {useAgent} from '#/state/session'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
export async function getPostgateRecord({
|
||||
agent,
|
||||
@@ -60,7 +61,10 @@ export async function getPostgateRecord({
|
||||
}),
|
||||
)
|
||||
|
||||
if (data.value && AppBskyFeedPostgate.isRecord(data.value)) {
|
||||
if (
|
||||
data.value &&
|
||||
bsky.validate(data.value, AppBskyFeedPostgate.validateRecord)
|
||||
) {
|
||||
return data.value
|
||||
} else {
|
||||
return undefined
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
$Typed,
|
||||
AppBskyEmbedRecord,
|
||||
AppBskyEmbedRecordWithMedia,
|
||||
AppBskyFeedDefs,
|
||||
@@ -45,8 +46,12 @@ export function mergePostgateRecords(
|
||||
})
|
||||
}
|
||||
|
||||
export function createEmbedViewDetachedRecord({uri}: {uri: string}) {
|
||||
const record: AppBskyEmbedRecord.ViewDetached = {
|
||||
export function createEmbedViewDetachedRecord({
|
||||
uri,
|
||||
}: {
|
||||
uri: string
|
||||
}): $Typed<AppBskyEmbedRecord.View> {
|
||||
const record: $Typed<AppBskyEmbedRecord.ViewDetached> = {
|
||||
$type: 'app.bsky.embed.record#viewDetached',
|
||||
uri,
|
||||
detached: true,
|
||||
@@ -95,7 +100,7 @@ export function createMaybeDetachedQuoteEmbed({
|
||||
|
||||
export function createEmbedViewRecordFromPost(
|
||||
post: AppBskyFeedDefs.PostView,
|
||||
): AppBskyEmbedRecord.ViewRecord {
|
||||
): $Typed<AppBskyEmbedRecord.ViewRecord> {
|
||||
return {
|
||||
$type: 'app.bsky.embed.record#viewRecord',
|
||||
uri: post.uri,
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
AtUri,
|
||||
BskyAgent,
|
||||
ComAtprotoRepoUploadBlob,
|
||||
Un$Typed,
|
||||
} from '@atproto/api'
|
||||
import {
|
||||
keepPreviousData,
|
||||
@@ -24,7 +25,12 @@ import {logEvent, LogEvents, toClout} from '#/lib/statsig/statsig'
|
||||
import {Shadow} from '#/state/cache/types'
|
||||
import {STALE} from '#/state/queries'
|
||||
import {resetProfilePostsQueries} from '#/state/queries/post-feed'
|
||||
import {
|
||||
unstableCacheProfileView,
|
||||
useUnstableProfileViewCache,
|
||||
} from '#/state/queries/unstable-profile-cache'
|
||||
import * as userActionHistory from '#/state/userActionHistory'
|
||||
import * as bsky from '#/types/bsky'
|
||||
import {updateProfileShadow} from '../cache/profile-shadow'
|
||||
import {useAgent, useSession} from '../session'
|
||||
import {
|
||||
@@ -35,6 +41,12 @@ import {RQKEY as RQKEY_LIST_CONVOS} from './messages/list-conversations'
|
||||
import {RQKEY as RQKEY_MY_BLOCKED} from './my-blocked-accounts'
|
||||
import {RQKEY as RQKEY_MY_MUTED} from './my-muted-accounts'
|
||||
|
||||
export * from '#/state/queries/unstable-profile-cache'
|
||||
/**
|
||||
* @deprecated use {@link unstableCacheProfileView} instead
|
||||
*/
|
||||
export const precacheProfile = unstableCacheProfileView
|
||||
|
||||
const RQKEY_ROOT = 'profile'
|
||||
export const RQKEY = (did: string) => [RQKEY_ROOT, did]
|
||||
|
||||
@@ -44,12 +56,6 @@ export const profilesQueryKey = (handles: string[]) => [
|
||||
handles,
|
||||
]
|
||||
|
||||
const profileBasicQueryKeyRoot = 'profileBasic'
|
||||
export const profileBasicQueryKey = (didOrHandle: string) => [
|
||||
profileBasicQueryKeyRoot,
|
||||
didOrHandle,
|
||||
]
|
||||
|
||||
export function useProfileQuery({
|
||||
did,
|
||||
staleTime = STALE.SECONDS.FIFTEEN,
|
||||
@@ -57,8 +63,8 @@ export function useProfileQuery({
|
||||
did: string | undefined
|
||||
staleTime?: number
|
||||
}) {
|
||||
const queryClient = useQueryClient()
|
||||
const agent = useAgent()
|
||||
const {getUnstableProfile} = useUnstableProfileViewCache()
|
||||
return useQuery<AppBskyActorDefs.ProfileViewDetailed>({
|
||||
// WARNING
|
||||
// this staleTime is load-bearing
|
||||
@@ -73,10 +79,7 @@ export function useProfileQuery({
|
||||
},
|
||||
placeholderData: () => {
|
||||
if (!did) return
|
||||
|
||||
return queryClient.getQueryData<AppBskyActorDefs.ProfileViewBasic>(
|
||||
profileBasicQueryKey(did),
|
||||
)
|
||||
return getUnstableProfile(did) as AppBskyActorDefs.ProfileViewDetailed
|
||||
},
|
||||
enabled: !!did,
|
||||
})
|
||||
@@ -121,10 +124,12 @@ export function usePrefetchProfileQuery() {
|
||||
}
|
||||
|
||||
interface ProfileUpdateParams {
|
||||
profile: AppBskyActorDefs.ProfileView
|
||||
profile: AppBskyActorDefs.ProfileViewDetailed
|
||||
updates:
|
||||
| AppBskyActorProfile.Record
|
||||
| ((existing: AppBskyActorProfile.Record) => AppBskyActorProfile.Record)
|
||||
| Un$Typed<AppBskyActorProfile.Record>
|
||||
| ((
|
||||
existing: Un$Typed<AppBskyActorProfile.Record>,
|
||||
) => Un$Typed<AppBskyActorProfile.Record>)
|
||||
newUserAvatar?: RNImage | undefined | null
|
||||
newUserBanner?: RNImage | undefined | null
|
||||
checkCommitted?: (res: AppBskyActorGetProfile.Response) => boolean
|
||||
@@ -161,29 +166,29 @@ export function useProfileUpdateMutation() {
|
||||
)
|
||||
}
|
||||
await agent.upsertProfile(async existing => {
|
||||
existing = existing || {}
|
||||
let next: Un$Typed<AppBskyActorProfile.Record> = existing || {}
|
||||
if (typeof updates === 'function') {
|
||||
existing = updates(existing)
|
||||
next = updates(next)
|
||||
} else {
|
||||
existing.displayName = updates.displayName
|
||||
existing.description = updates.description
|
||||
next.displayName = updates.displayName
|
||||
next.description = updates.description
|
||||
if ('pinnedPost' in updates) {
|
||||
existing.pinnedPost = updates.pinnedPost
|
||||
next.pinnedPost = updates.pinnedPost
|
||||
}
|
||||
}
|
||||
if (newUserAvatarPromise) {
|
||||
const res = await newUserAvatarPromise
|
||||
existing.avatar = res.data.blob
|
||||
next.avatar = res.data.blob
|
||||
} else if (newUserAvatar === null) {
|
||||
existing.avatar = undefined
|
||||
next.avatar = undefined
|
||||
}
|
||||
if (newUserBannerPromise) {
|
||||
const res = await newUserBannerPromise
|
||||
existing.banner = res.data.blob
|
||||
next.banner = res.data.blob
|
||||
} else if (newUserBanner === null) {
|
||||
existing.banner = undefined
|
||||
next.banner = undefined
|
||||
}
|
||||
return existing
|
||||
return next
|
||||
})
|
||||
await whenAppViewReady(
|
||||
agent,
|
||||
@@ -228,7 +233,7 @@ export function useProfileUpdateMutation() {
|
||||
}
|
||||
|
||||
export function useProfileFollowMutationQueue(
|
||||
profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>,
|
||||
profile: Shadow<bsky.profile.AnyProfileView>,
|
||||
logContext: LogEvents['profile:follow']['logContext'] &
|
||||
LogEvents['profile:follow']['logContext'],
|
||||
) {
|
||||
@@ -302,7 +307,7 @@ export function useProfileFollowMutationQueue(
|
||||
|
||||
function useProfileFollowMutation(
|
||||
logContext: LogEvents['profile:follow']['logContext'],
|
||||
profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>,
|
||||
profile: Shadow<bsky.profile.AnyProfileView>,
|
||||
) {
|
||||
const {currentAccount} = useSession()
|
||||
const agent = useAgent()
|
||||
@@ -321,7 +326,10 @@ function useProfileFollowMutation(
|
||||
didBecomeMutual: profile.viewer
|
||||
? Boolean(profile.viewer.followedBy)
|
||||
: undefined,
|
||||
followeeClout: toClout(profile.followersCount),
|
||||
followeeClout:
|
||||
'followersCount' in profile
|
||||
? toClout(profile.followersCount)
|
||||
: undefined,
|
||||
followerClout: toClout(ownProfile?.followersCount),
|
||||
})
|
||||
return await agent.follow(did)
|
||||
@@ -342,7 +350,7 @@ function useProfileUnfollowMutation(
|
||||
}
|
||||
|
||||
export function useProfileMuteMutationQueue(
|
||||
profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>,
|
||||
profile: Shadow<bsky.profile.AnyProfileView>,
|
||||
) {
|
||||
const queryClient = useQueryClient()
|
||||
const did = profile.did
|
||||
@@ -417,7 +425,7 @@ function useProfileUnmuteMutation() {
|
||||
}
|
||||
|
||||
export function useProfileBlockMutationQueue(
|
||||
profile: Shadow<AppBskyActorDefs.ProfileViewBasic>,
|
||||
profile: Shadow<bsky.profile.AnyProfileView>,
|
||||
) {
|
||||
const queryClient = useQueryClient()
|
||||
const did = profile.did
|
||||
@@ -513,14 +521,6 @@ function useProfileUnblockMutation() {
|
||||
})
|
||||
}
|
||||
|
||||
export function precacheProfile(
|
||||
queryClient: QueryClient,
|
||||
profile: AppBskyActorDefs.ProfileViewBasic,
|
||||
) {
|
||||
queryClient.setQueryData(profileBasicQueryKey(profile.handle), profile)
|
||||
queryClient.setQueryData(profileBasicQueryKey(profile.did), profile)
|
||||
}
|
||||
|
||||
async function whenAppViewReady(
|
||||
agent: BskyAgent,
|
||||
actor: string,
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
import {AppBskyActorDefs, AtUri} from '@atproto/api'
|
||||
import {
|
||||
QueryClient,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
UseQueryResult,
|
||||
} from '@tanstack/react-query'
|
||||
import {AtUri} from '@atproto/api'
|
||||
import {QueryClient, useQuery, UseQueryResult} from '@tanstack/react-query'
|
||||
|
||||
import {STALE} from '#/state/queries'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {profileBasicQueryKey as RQKEY_PROFILE_BASIC} from './profile'
|
||||
import {useUnstableProfileViewCache} from './profile'
|
||||
|
||||
const RQKEY_ROOT = 'resolved-did'
|
||||
export const RQKEY = (didOrHandle: string) => [RQKEY_ROOT, didOrHandle]
|
||||
@@ -28,8 +23,8 @@ export function useResolveUriQuery(uri: string | undefined): UriUseQueryResult {
|
||||
}
|
||||
|
||||
export function useResolveDidQuery(didOrHandle: string | undefined) {
|
||||
const queryClient = useQueryClient()
|
||||
const agent = useAgent()
|
||||
const {getUnstableProfile} = useUnstableProfileViewCache()
|
||||
|
||||
return useQuery<string, Error>({
|
||||
staleTime: STALE.HOURS.ONE,
|
||||
@@ -45,11 +40,7 @@ export function useResolveDidQuery(didOrHandle: string | undefined) {
|
||||
initialData: () => {
|
||||
// Return undefined if no did or handle
|
||||
if (!didOrHandle) return
|
||||
|
||||
const profile =
|
||||
queryClient.getQueryData<AppBskyActorDefs.ProfileViewBasic>(
|
||||
RQKEY_PROFILE_BASIC(didOrHandle),
|
||||
)
|
||||
const profile = getUnstableProfile(didOrHandle)
|
||||
return profile?.did
|
||||
},
|
||||
enabled: !!didOrHandle,
|
||||
|
||||
@@ -174,7 +174,7 @@ export function* findAllPostsInQueryData(
|
||||
export function* findAllProfilesInQueryData(
|
||||
queryClient: QueryClient,
|
||||
did: string,
|
||||
): Generator<AppBskyActorDefs.ProfileView, undefined> {
|
||||
): Generator<AppBskyActorDefs.ProfileViewBasic, undefined> {
|
||||
const queryDatas = queryClient.getQueriesData<
|
||||
InfiniteData<AppBskyFeedSearchPosts.OutputSchema>
|
||||
>({
|
||||
|
||||
@@ -19,6 +19,7 @@ export function useServiceConfigQuery() {
|
||||
const {data} = await agent.api.app.bsky.unspecced.getConfig()
|
||||
return {
|
||||
checkEmailConfirmed: Boolean(data.checkEmailConfirmed),
|
||||
// @ts-expect-error not included in types atm
|
||||
topicsEnabled: Boolean(data.topicsEnabled),
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {
|
||||
AppBskyActorDefs,
|
||||
AppBskyFeedDefs,
|
||||
AppBskyGraphDefs,
|
||||
AppBskyGraphGetStarterPack,
|
||||
@@ -29,6 +28,7 @@ import {invalidateActorStarterPacksQuery} from '#/state/queries/actor-starter-pa
|
||||
import {STALE} from '#/state/queries/index'
|
||||
import {invalidateListMembersQuery} from '#/state/queries/list-members'
|
||||
import {useAgent} from '#/state/session'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
const RQKEY_ROOT = 'starter-pack'
|
||||
const RQKEY = ({
|
||||
@@ -93,7 +93,7 @@ export async function invalidateStarterPack({
|
||||
interface UseCreateStarterPackMutationParams {
|
||||
name: string
|
||||
description?: string
|
||||
profiles: AppBskyActorDefs.ProfileViewBasic[]
|
||||
profiles: bsky.profile.AnyProfileView[]
|
||||
feeds?: AppBskyFeedDefs.GeneratorView[]
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ export function useCreateStarterPackMutation({
|
||||
|
||||
return await agent.app.bsky.graph.starterpack.create(
|
||||
{
|
||||
repo: agent.session?.did,
|
||||
repo: agent.assertDid,
|
||||
},
|
||||
{
|
||||
name,
|
||||
@@ -366,7 +366,10 @@ export async function precacheStarterPack(
|
||||
let starterPackView: AppBskyGraphDefs.StarterPackView | undefined
|
||||
if (AppBskyGraphDefs.isStarterPackView(starterPack)) {
|
||||
starterPackView = starterPack
|
||||
} else if (AppBskyGraphDefs.isStarterPackViewBasic(starterPack)) {
|
||||
} else if (
|
||||
AppBskyGraphDefs.isStarterPackViewBasic(starterPack) &&
|
||||
bsky.validate(starterPack.record, AppBskyGraphStarterpack.validateRecord)
|
||||
) {
|
||||
const listView: AppBskyGraphDefs.ListViewBasic = {
|
||||
uri: starterPack.record.list,
|
||||
// This will be populated once the data from server is fetched
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
} from '#/state/queries/threadgate/util'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {useThreadgateHiddenReplyUrisAPI} from '#/state/threadgate-hidden-replies'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
export * from '#/state/queries/threadgate/types'
|
||||
export * from '#/state/queries/threadgate/util'
|
||||
@@ -138,7 +139,10 @@ export async function getThreadgateRecord({
|
||||
}),
|
||||
)
|
||||
|
||||
if (data.value && AppBskyFeedThreadgate.isRecord(data.value)) {
|
||||
if (
|
||||
data.value &&
|
||||
bsky.validate(data.value, AppBskyFeedThreadgate.validateRecord)
|
||||
) {
|
||||
return data.value
|
||||
} else {
|
||||
return null
|
||||
|
||||
@@ -4,4 +4,4 @@ export type ThreadgateAllowUISetting =
|
||||
| {type: 'mention'}
|
||||
| {type: 'following'}
|
||||
| {type: 'followers'}
|
||||
| {type: 'list'; list: unknown}
|
||||
| {type: 'list'; list: string}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import {AppBskyFeedDefs, AppBskyFeedThreadgate} from '@atproto/api'
|
||||
|
||||
import {ThreadgateAllowUISetting} from '#/state/queries/threadgate/types'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
export function threadgateViewToAllowUISetting(
|
||||
threadgateView: AppBskyFeedDefs.ThreadgateView | undefined,
|
||||
): ThreadgateAllowUISetting[] {
|
||||
// Validate the record for clarity, since backwards compat code is a little confusing
|
||||
const threadgate =
|
||||
threadgateView &&
|
||||
AppBskyFeedThreadgate.isRecord(threadgateView.record) &&
|
||||
AppBskyFeedThreadgate.validateRecord(threadgateView.record).success
|
||||
bsky.validate(threadgateView.record, AppBskyFeedThreadgate.validateRecord)
|
||||
? threadgateView.record
|
||||
: undefined
|
||||
return threadgateRecordToAllowUISetting(threadgate)
|
||||
@@ -39,14 +40,14 @@ export function threadgateRecordToAllowUISetting(
|
||||
const settings: ThreadgateAllowUISetting[] = threadgate.allow
|
||||
.map(allow => {
|
||||
let setting: ThreadgateAllowUISetting | undefined
|
||||
if (allow.$type === 'app.bsky.feed.threadgate#mentionRule') {
|
||||
if (AppBskyFeedThreadgate.isMentionRule(allow)) {
|
||||
setting = {type: 'mention'}
|
||||
} else if (allow.$type === 'app.bsky.feed.threadgate#followingRule') {
|
||||
} else if (AppBskyFeedThreadgate.isFollowingRule(allow)) {
|
||||
setting = {type: 'following'}
|
||||
} else if (allow.$type === 'app.bsky.feed.threadgate#followerRule') {
|
||||
setting = {type: 'followers'}
|
||||
} else if (allow.$type === 'app.bsky.feed.threadgate#listRule') {
|
||||
} else if (AppBskyFeedThreadgate.isListRule(allow)) {
|
||||
setting = {type: 'list', list: allow.list}
|
||||
} else if (AppBskyFeedThreadgate.isFollowerRule(allow)) {
|
||||
setting = {type: 'followers'}
|
||||
}
|
||||
return setting
|
||||
})
|
||||
@@ -69,11 +70,7 @@ export function threadgateAllowUISettingToAllowRecordValue(
|
||||
return undefined
|
||||
}
|
||||
|
||||
let allow: (
|
||||
| AppBskyFeedThreadgate.MentionRule
|
||||
| AppBskyFeedThreadgate.FollowingRule
|
||||
| AppBskyFeedThreadgate.ListRule
|
||||
)[] = []
|
||||
let allow: Exclude<AppBskyFeedThreadgate.Record['allow'], undefined> = []
|
||||
|
||||
if (!threadgate.find(v => v.type === 'nobody')) {
|
||||
for (const rule of threadgate) {
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import {useCallback} from 'react'
|
||||
import {QueryClient, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
const unstableProfileViewCacheQueryKeyRoot = 'unstableProfileViewCache'
|
||||
export const unstableProfileViewCacheQueryKey = (didOrHandle: string) => [
|
||||
unstableProfileViewCacheQueryKeyRoot,
|
||||
didOrHandle,
|
||||
]
|
||||
|
||||
/**
|
||||
* Used as a rough cache of profile views to make loading snappier. This method
|
||||
* accepts and stores any profile view type by both handle and DID.
|
||||
*
|
||||
* Access the cache via {@link useUnstableProfileViewCache}.
|
||||
*/
|
||||
export function unstableCacheProfileView(
|
||||
queryClient: QueryClient,
|
||||
profile: bsky.profile.AnyProfileView,
|
||||
) {
|
||||
queryClient.setQueryData(
|
||||
unstableProfileViewCacheQueryKey(profile.handle),
|
||||
profile,
|
||||
)
|
||||
queryClient.setQueryData(
|
||||
unstableProfileViewCacheQueryKey(profile.did),
|
||||
profile,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to access the unstable profile view cache. This cache can return ANY
|
||||
* profile view type, so if the object shape is important, you need to use the
|
||||
* identity validators shipped in the atproto SDK e.g.
|
||||
* `AppBskyActorDefs.isValidProfileViewBasic` to confirm before using.
|
||||
*
|
||||
* To cache a profile, use {@link unstableCacheProfileView}.
|
||||
*/
|
||||
export function useUnstableProfileViewCache() {
|
||||
const qc = useQueryClient()
|
||||
const getUnstableProfile = useCallback(
|
||||
(didOrHandle: string) => {
|
||||
return qc.getQueryData<bsky.profile.AnyProfileView>(
|
||||
unstableProfileViewCacheQueryKey(didOrHandle),
|
||||
)
|
||||
},
|
||||
[qc],
|
||||
)
|
||||
return {getUnstableProfile}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
} from '@atproto/api'
|
||||
import {InfiniteData, QueryClient, QueryKey} from '@tanstack/react-query'
|
||||
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
export async function truncateAndInvalidate<T = any>(
|
||||
queryClient: QueryClient,
|
||||
queryKey: QueryKey,
|
||||
@@ -44,7 +46,9 @@ export function didOrHandleUriMatches(
|
||||
export function getEmbeddedPost(
|
||||
v: unknown,
|
||||
): AppBskyEmbedRecord.ViewRecord | undefined {
|
||||
if (AppBskyEmbedRecord.isView(v)) {
|
||||
if (
|
||||
bsky.dangerousIsType<AppBskyEmbedRecord.View>(v, AppBskyEmbedRecord.isView)
|
||||
) {
|
||||
if (
|
||||
AppBskyEmbedRecord.isViewRecord(v.record) &&
|
||||
AppBskyFeedPost.isRecord(v.record.value)
|
||||
@@ -52,7 +56,12 @@ export function getEmbeddedPost(
|
||||
return v.record
|
||||
}
|
||||
}
|
||||
if (AppBskyEmbedRecordWithMedia.isView(v)) {
|
||||
if (
|
||||
bsky.dangerousIsType<AppBskyEmbedRecordWithMedia.View>(
|
||||
v,
|
||||
AppBskyEmbedRecordWithMedia.isView,
|
||||
)
|
||||
) {
|
||||
if (
|
||||
AppBskyEmbedRecord.isViewRecord(v.record.record) &&
|
||||
AppBskyFeedPost.isRecord(v.record.record.value)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from 'react'
|
||||
import {
|
||||
AppBskyActorDefs,
|
||||
AppBskyEmbedRecord,
|
||||
AppBskyFeedDefs,
|
||||
ModerationDecision,
|
||||
} from '@atproto/api'
|
||||
@@ -21,7 +20,7 @@ export interface ComposerOptsPostRef {
|
||||
cid: string
|
||||
text: string
|
||||
author: AppBskyActorDefs.ProfileViewBasic
|
||||
embed?: AppBskyEmbedRecord.ViewRecord['embed']
|
||||
embed?: AppBskyFeedDefs.PostView['embed']
|
||||
moderation?: ModerationDecision
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user