diff options
Diffstat (limited to 'src/state')
20 files changed, 259 insertions, 63 deletions
diff --git a/src/state/feed-feedback.tsx b/src/state/feed-feedback.tsx index 8b235f492..3e9c2bafa 100644 --- a/src/state/feed-feedback.tsx +++ b/src/state/feed-feedback.tsx @@ -10,17 +10,58 @@ import {AppState, type AppStateStatus} from 'react-native' import {type AppBskyFeedDefs} from '@atproto/api' import throttle from 'lodash.throttle' -import {FEEDBACK_FEEDS, STAGING_FEEDS} from '#/lib/constants' +import {PROD_FEEDS, STAGING_FEEDS} from '#/lib/constants' import {isNetworkError} from '#/lib/hooks/useCleanError' import {logEvent} from '#/lib/statsig/statsig' import {Logger} from '#/logger' import { + type FeedSourceFeedInfo, + type FeedSourceInfo, + isFeedSourceFeedInfo, +} from '#/state/queries/feed' +import { type FeedDescriptor, type FeedPostSliceItem, } from '#/state/queries/post-feed' import {getItemsForFeedback} from '#/view/com/posts/PostFeed' import {useAgent} from './session' +export const FEEDBACK_FEEDS = [...PROD_FEEDS, ...STAGING_FEEDS] + +export const PASSIVE_FEEDBACK_INTERACTIONS = [ + 'app.bsky.feed.defs#clickthroughItem', + 'app.bsky.feed.defs#clickthroughAuthor', + 'app.bsky.feed.defs#clickthroughReposter', + 'app.bsky.feed.defs#clickthroughEmbed', + 'app.bsky.feed.defs#interactionSeen', +] as const + +export type PassiveFeedbackInteraction = + (typeof PASSIVE_FEEDBACK_INTERACTIONS)[number] + +export const DIRECT_FEEDBACK_INTERACTIONS = [ + 'app.bsky.feed.defs#requestLess', + 'app.bsky.feed.defs#requestMore', +] as const + +export type DirectFeedbackInteraction = + (typeof DIRECT_FEEDBACK_INTERACTIONS)[number] + +export const ALL_FEEDBACK_INTERACTIONS = [ + ...PASSIVE_FEEDBACK_INTERACTIONS, + ...DIRECT_FEEDBACK_INTERACTIONS, +] as const + +export type FeedbackInteraction = (typeof ALL_FEEDBACK_INTERACTIONS)[number] + +export function isFeedbackInteraction( + interactionEvent: string, +): interactionEvent is FeedbackInteraction { + return ALL_FEEDBACK_INTERACTIONS.includes( + interactionEvent as FeedbackInteraction, + ) +} + const logger = Logger.create(Logger.Context.FeedFeedback) export type StateContext = { @@ -28,6 +69,7 @@ export type StateContext = { onItemSeen: (item: any) => void sendInteraction: (interaction: AppBskyFeedDefs.Interaction) => void feedDescriptor: FeedDescriptor | undefined + feedSourceInfo: FeedSourceInfo | undefined } const stateContext = createContext<StateContext>({ @@ -35,15 +77,27 @@ const stateContext = createContext<StateContext>({ onItemSeen: (_item: any) => {}, sendInteraction: (_interaction: AppBskyFeedDefs.Interaction) => {}, feedDescriptor: undefined, + feedSourceInfo: undefined, }) stateContext.displayName = 'FeedFeedbackContext' export function useFeedFeedback( - feed: FeedDescriptor | undefined, + feedSourceInfo: FeedSourceInfo | undefined, hasSession: boolean, ) { const agent = useAgent() - const enabled = isDiscoverFeed(feed) && hasSession + + const feed = + !!feedSourceInfo && isFeedSourceFeedInfo(feedSourceInfo) + ? feedSourceInfo + : undefined + + const isDiscover = isDiscoverFeed(feed?.feedDescriptor) + const acceptsInteractions = Boolean(isDiscover || feed?.acceptsInteractions) + const proxyDid = feed?.view?.did + const enabled = + Boolean(feed) && Boolean(proxyDid) && acceptsInteractions && hasSession + const enabledInteractions = getEnabledInteractions(enabled, feed, isDiscover) const queue = useRef<Set<string>>(new Set()) const history = useRef< @@ -66,19 +120,24 @@ export function useFeedFeedback( const interactions = Array.from(queue.current).map(toInteraction) queue.current.clear() - let proxyDid = 'did:web:discover.bsky.app' - if (STAGING_FEEDS.includes(feed ?? '')) { - proxyDid = 'did:web:algo.pop2.bsky.app' + const interactionsToSend = interactions.filter( + interaction => + interaction.event && + isFeedbackInteraction(interaction.event) && + enabledInteractions.includes(interaction.event), + ) + + if (interactionsToSend.length === 0) { + return } // Send to the feed agent.app.bsky.feed .sendInteractions( - {interactions}, + {interactions: interactionsToSend}, { encoding: 'application/json', headers: { - // TODO when we start sending to other feeds, we need to grab their DID -prf 'atproto-proxy': `${proxyDid}#bsky_fg`, }, }, @@ -93,10 +152,13 @@ export function useFeedFeedback( if (aggregatedStats.current === null) { aggregatedStats.current = createAggregatedStats() } - sendOrAggregateInteractionsForStats(aggregatedStats.current, interactions) + sendOrAggregateInteractionsForStats( + aggregatedStats.current, + interactionsToSend, + ) throttledFlushAggregatedStats() logger.debug('flushed') - }, [agent, throttledFlushAggregatedStats, feed]) + }, [agent, throttledFlushAggregatedStats, proxyDid, enabledInteractions]) const sendToFeed = useMemo( () => @@ -168,7 +230,8 @@ export function useFeedFeedback( // call on various events // queues the event to be sent with the throttled sendToFeed call sendInteraction, - feedDescriptor: feed, + feedDescriptor: feed?.feedDescriptor, + feedSourceInfo: typeof feed === 'object' ? feed : undefined, } }, [enabled, onItemSeen, sendInteraction, feed]) } @@ -184,10 +247,21 @@ export function useFeedFeedbackContext() { // take advantage of the feed feedback API. Until that's in // place, we're hardcoding it to the discover feed. // -prf -function isDiscoverFeed(feed?: FeedDescriptor) { +export function isDiscoverFeed(feed?: FeedDescriptor) { return !!feed && FEEDBACK_FEEDS.includes(feed) } +function getEnabledInteractions( + enabled: boolean, + feed: FeedSourceFeedInfo | undefined, + isDiscover: boolean, +): readonly FeedbackInteraction[] { + if (!enabled || !feed) { + return [] + } + return isDiscover ? ALL_FEEDBACK_INTERACTIONS : DIRECT_FEEDBACK_INTERACTIONS +} + function toString(interaction: AppBskyFeedDefs.Interaction): string { return `${interaction.item}|${interaction.event}|${ interaction.feedContext || '' diff --git a/src/state/messages/convo/agent.ts b/src/state/messages/convo/agent.ts index 2ad4c592e..168002b1f 100644 --- a/src/state/messages/convo/agent.ts +++ b/src/state/messages/convo/agent.ts @@ -10,6 +10,7 @@ import EventEmitter from 'eventemitter3' import {nanoid} from 'nanoid/non-secure' import {networkRetry} from '#/lib/async/retry' +import {DM_SERVICE_HEADERS} from '#/lib/constants' import {isNetworkError} from '#/lib/strings/errors' import {Logger} from '#/logger' import {isNative} from '#/platform/detection' @@ -33,7 +34,6 @@ import { } from '#/state/messages/convo/types' import {type MessagesEventBus} from '#/state/messages/events/agent' import {type MessagesEventBusError} from '#/state/messages/events/types' -import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const' const logger = Logger.create(Logger.Context.ConversationAgent) diff --git a/src/state/messages/events/agent.ts b/src/state/messages/events/agent.ts index fb3047bf6..e54ea1c77 100644 --- a/src/state/messages/events/agent.ts +++ b/src/state/messages/events/agent.ts @@ -3,6 +3,7 @@ import EventEmitter from 'eventemitter3' import {nanoid} from 'nanoid/non-secure' import {networkRetry} from '#/lib/async/retry' +import {DM_SERVICE_HEADERS} from '#/lib/constants' import {isNetworkError} from '#/lib/strings/errors' import {Logger} from '#/logger' import { @@ -17,7 +18,6 @@ import { type MessagesEventBusParams, MessagesEventBusStatus, } from '#/state/messages/events/types' -import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const' const logger = Logger.create(Logger.Context.DMsAgent) diff --git a/src/state/modals/index.tsx b/src/state/modals/index.tsx index 9197a66c9..c6070e97b 100644 --- a/src/state/modals/index.tsx +++ b/src/state/modals/index.tsx @@ -35,25 +35,15 @@ export interface ContentLanguagesSettingsModal { name: 'content-languages-settings' } -export interface PostLanguagesSettingsModal { - name: 'post-languages-settings' -} - -export interface ChangePasswordModal { - name: 'change-password' -} - /** * @deprecated DO NOT ADD NEW MODALS */ export type Modal = // Account | DeleteAccountModal - | ChangePasswordModal // Curation | ContentLanguagesSettingsModal - | PostLanguagesSettingsModal // Lists | CreateOrEditListModal diff --git a/src/state/queries/actor-starter-packs.ts b/src/state/queries/actor-starter-packs.ts index 670544dfe..d40e05453 100644 --- a/src/state/queries/actor-starter-packs.ts +++ b/src/state/queries/actor-starter-packs.ts @@ -1,15 +1,23 @@ -import {AppBskyGraphGetActorStarterPacks} from '@atproto/api' import { - InfiniteData, - QueryClient, - QueryKey, + type AppBskyGraphGetActorStarterPacks, + type AppBskyGraphGetStarterPacksWithMembership, +} from '@atproto/api' +import { + type InfiniteData, + type QueryClient, + type QueryKey, useInfiniteQuery, } from '@tanstack/react-query' import {useAgent} from '#/state/session' export const RQKEY_ROOT = 'actor-starter-packs' +export const RQKEY_WITH_MEMBERSHIP_ROOT = 'actor-starter-packs-with-membership' export const RQKEY = (did?: string) => [RQKEY_ROOT, did] +export const RQKEY_WITH_MEMBERSHIP = (did?: string) => [ + RQKEY_WITH_MEMBERSHIP_ROOT, + did, +] export function useActorStarterPacksQuery({ did, @@ -42,6 +50,37 @@ export function useActorStarterPacksQuery({ }) } +export function useActorStarterPacksWithMembershipsQuery({ + did, + enabled = true, +}: { + did?: string + enabled?: boolean +}) { + const agent = useAgent() + + return useInfiniteQuery< + AppBskyGraphGetStarterPacksWithMembership.OutputSchema, + Error, + InfiniteData<AppBskyGraphGetStarterPacksWithMembership.OutputSchema>, + QueryKey, + string | undefined + >({ + queryKey: RQKEY_WITH_MEMBERSHIP(did), + queryFn: async ({pageParam}: {pageParam?: string}) => { + const res = await agent.app.bsky.graph.getStarterPacksWithMembership({ + actor: did!, + limit: 10, + cursor: pageParam, + }) + return res.data + }, + enabled: Boolean(did) && enabled, + initialPageParam: undefined, + getNextPageParam: lastPage => lastPage.cursor, + }) +} + export async function invalidateActorStarterPacksQuery({ queryClient, did, @@ -51,3 +90,13 @@ export async function invalidateActorStarterPacksQuery({ }) { await queryClient.invalidateQueries({queryKey: RQKEY(did)}) } + +export async function invalidateActorStarterPacksWithMembershipQuery({ + queryClient, + did, +}: { + queryClient: QueryClient + did: string +}) { + await queryClient.invalidateQueries({queryKey: RQKEY_WITH_MEMBERSHIP(did)}) +} diff --git a/src/state/queries/feed.ts b/src/state/queries/feed.ts index 89023e513..e6e3e82fb 100644 --- a/src/state/queries/feed.ts +++ b/src/state/queries/feed.ts @@ -48,6 +48,7 @@ export type FeedSourceFeedInfo = { creatorDid: string creatorHandle: string likeCount: number | undefined + acceptsInteractions?: boolean likeUri: string | undefined contentMode: AppBskyFeedDefs.GeneratorView['contentMode'] } @@ -73,6 +74,12 @@ export type FeedSourceListInfo = { export type FeedSourceInfo = FeedSourceFeedInfo | FeedSourceListInfo +export function isFeedSourceFeedInfo( + feed: FeedSourceInfo, +): feed is FeedSourceFeedInfo { + return feed.type === 'feed' +} + const feedSourceInfoQueryKeyRoot = 'getFeedSourceInfo' export const feedSourceInfoQueryKey = ({uri}: {uri: string}) => [ feedSourceInfoQueryKeyRoot, @@ -115,6 +122,7 @@ export function hydrateFeedGenerator( creatorDid: view.creator.did, creatorHandle: view.creator.handle, likeCount: view.likeCount, + acceptsInteractions: view.acceptsInteractions, likeUri: view.viewer?.like, contentMode: view.contentMode, } @@ -619,6 +627,29 @@ export function useSavedFeeds() { }) } +const feedInfoQueryKeyRoot = 'feedInfo' + +export function useFeedInfo(feedUri: string | undefined) { + const agent = useAgent() + + return useQuery({ + staleTime: STALE.INFINITY, + queryKey: [feedInfoQueryKeyRoot, feedUri], + queryFn: async () => { + if (!feedUri) { + return undefined + } + + const res = await agent.app.bsky.feed.getFeedGenerator({ + feed: feedUri, + }) + + const feedSourceInfo = hydrateFeedGenerator(res.data.view) + return feedSourceInfo + }, + }) +} + function precacheFeed(queryClient: QueryClient, hydratedFeed: FeedSourceInfo) { precacheResolvedUri( queryClient, diff --git a/src/state/queries/handle-availability.ts b/src/state/queries/handle-availability.ts index 9391f5d09..06fc6eebb 100644 --- a/src/state/queries/handle-availability.ts +++ b/src/state/queries/handle-availability.ts @@ -1,4 +1,4 @@ -import {Agent, ComAtprotoTempCheckHandleAvailability} from '@atproto/api' +import {ComAtprotoTempCheckHandleAvailability} from '@atproto/api' import {useQuery} from '@tanstack/react-query' import { @@ -10,6 +10,7 @@ import {createFullHandle} from '#/lib/strings/handles' import {logger} from '#/logger' import {useDebouncedValue} from '#/components/live/utils' import * as bsky from '#/types/bsky' +import {Agent} from '../session/agent' export const RQKEY_handleAvailability = ( handle: string, @@ -74,7 +75,7 @@ export async function checkHandleAvailability( }, ) { if (serviceDid === BSKY_SERVICE_DID) { - const agent = new Agent({service: BSKY_SERVICE}) + const agent = new Agent(null, {service: BSKY_SERVICE}) // entryway has a special API for handle availability const {data} = await agent.com.atproto.temp.checkHandleAvailability({ handle, @@ -109,7 +110,7 @@ export async function checkHandleAvailability( } } else { // 3rd party PDSes won't have this API so just try and resolve the handle - const agent = new Agent({service: PUBLIC_BSKY_SERVICE}) + const agent = new Agent(null, {service: PUBLIC_BSKY_SERVICE}) try { const res = await agent.resolveHandle({ handle, diff --git a/src/state/queries/messages/accept-conversation.ts b/src/state/queries/messages/accept-conversation.ts index 82acb33c8..0c06055b5 100644 --- a/src/state/queries/messages/accept-conversation.ts +++ b/src/state/queries/messages/accept-conversation.ts @@ -1,9 +1,12 @@ -import {ChatBskyConvoAcceptConvo, ChatBskyConvoListConvos} from '@atproto/api' +import { + type ChatBskyConvoAcceptConvo, + type ChatBskyConvoListConvos, +} from '@atproto/api' import {useMutation, useQueryClient} from '@tanstack/react-query' +import {DM_SERVICE_HEADERS} from '#/lib/constants' import {logger} from '#/logger' import {useAgent} from '#/state/session' -import {DM_SERVICE_HEADERS} from './const' import { RQKEY as CONVO_LIST_KEY, RQKEY_ROOT as CONVO_LIST_ROOT_KEY, diff --git a/src/state/queries/messages/const.ts b/src/state/queries/messages/const.ts deleted file mode 100644 index 1c5519a63..000000000 --- a/src/state/queries/messages/const.ts +++ /dev/null @@ -1,5 +0,0 @@ -import {CHAT_PROXY_DID} from '#/env' - -export const DM_SERVICE_HEADERS = { - 'atproto-proxy': `${CHAT_PROXY_DID}#bsky_chat`, -} diff --git a/src/state/queries/messages/conversation.ts b/src/state/queries/messages/conversation.ts index de5a90571..393bf9e52 100644 --- a/src/state/queries/messages/conversation.ts +++ b/src/state/queries/messages/conversation.ts @@ -1,17 +1,17 @@ -import {ChatBskyConvoDefs} from '@atproto/api' +import {type ChatBskyConvoDefs} from '@atproto/api' import { - QueryClient, + type QueryClient, useMutation, useQuery, useQueryClient, } from '@tanstack/react-query' +import {DM_SERVICE_HEADERS} from '#/lib/constants' import {STALE} from '#/state/queries' -import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const' import {useOnMarkAsRead} from '#/state/queries/messages/list-conversations' import {useAgent} from '#/state/session' import { - ConvoListQueryData, + type ConvoListQueryData, getConvoFromQueryData, RQKEY_ROOT as LIST_CONVOS_KEY, } from './list-conversations' diff --git a/src/state/queries/messages/get-convo-availability.ts b/src/state/queries/messages/get-convo-availability.ts index f545c3bba..2392edb09 100644 --- a/src/state/queries/messages/get-convo-availability.ts +++ b/src/state/queries/messages/get-convo-availability.ts @@ -1,6 +1,6 @@ import {useQuery} from '@tanstack/react-query' -import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const' +import {DM_SERVICE_HEADERS} from '#/lib/constants' import {useAgent} from '#/state/session' import {STALE} from '..' diff --git a/src/state/queries/messages/get-convo-for-members.ts b/src/state/queries/messages/get-convo-for-members.ts index 3f45c2328..58c1ab524 100644 --- a/src/state/queries/messages/get-convo-for-members.ts +++ b/src/state/queries/messages/get-convo-for-members.ts @@ -1,8 +1,8 @@ -import {ChatBskyConvoGetConvoForMembers} from '@atproto/api' +import {type ChatBskyConvoGetConvoForMembers} from '@atproto/api' import {useMutation, useQueryClient} from '@tanstack/react-query' +import {DM_SERVICE_HEADERS} from '#/lib/constants' import {logger} from '#/logger' -import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const' import {useAgent} from '#/state/session' import {precacheConvoQuery} from './conversation' diff --git a/src/state/queries/messages/leave-conversation.ts b/src/state/queries/messages/leave-conversation.ts index b17e515be..986351a07 100644 --- a/src/state/queries/messages/leave-conversation.ts +++ b/src/state/queries/messages/leave-conversation.ts @@ -1,13 +1,16 @@ import {useMemo} from 'react' -import {ChatBskyConvoLeaveConvo, ChatBskyConvoListConvos} from '@atproto/api' +import { + type ChatBskyConvoLeaveConvo, + type ChatBskyConvoListConvos, +} from '@atproto/api' import { useMutation, useMutationState, useQueryClient, } from '@tanstack/react-query' +import {DM_SERVICE_HEADERS} from '#/lib/constants' import {logger} from '#/logger' -import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const' import {useAgent} from '#/state/session' import {RQKEY_ROOT as CONVO_LIST_KEY} from './list-conversations' diff --git a/src/state/queries/messages/list-conversations.tsx b/src/state/queries/messages/list-conversations.tsx index 3f8252519..c5457d1cb 100644 --- a/src/state/queries/messages/list-conversations.tsx +++ b/src/state/queries/messages/list-conversations.tsx @@ -13,10 +13,10 @@ import { } from '@tanstack/react-query' import throttle from 'lodash.throttle' +import {DM_SERVICE_HEADERS} from '#/lib/constants' import {useCurrentConvoId} from '#/state/messages/current-convo-id' import {useMessagesEventBus} from '#/state/messages/events' import {useModerationOpts} from '#/state/preferences/moderation-opts' -import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const' import {useAgent, useSession} from '#/state/session' import {useLeftConvos} from './leave-conversation' diff --git a/src/state/queries/messages/mute-conversation.ts b/src/state/queries/messages/mute-conversation.ts index da9644145..d668e36cb 100644 --- a/src/state/queries/messages/mute-conversation.ts +++ b/src/state/queries/messages/mute-conversation.ts @@ -1,11 +1,15 @@ import { - ChatBskyConvoDefs, - ChatBskyConvoListConvos, - ChatBskyConvoMuteConvo, + type ChatBskyConvoDefs, + type ChatBskyConvoListConvos, + type ChatBskyConvoMuteConvo, } from '@atproto/api' -import {InfiniteData, useMutation, useQueryClient} from '@tanstack/react-query' +import { + type InfiniteData, + useMutation, + useQueryClient, +} from '@tanstack/react-query' -import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const' +import {DM_SERVICE_HEADERS} from '#/lib/constants' import {useAgent} from '#/state/session' import {RQKEY as CONVO_KEY} from './conversation' import {RQKEY_ROOT as CONVO_LIST_KEY} from './list-conversations' diff --git a/src/state/queries/messages/update-all-read.ts b/src/state/queries/messages/update-all-read.ts index 72fa65ee6..3d0fd3a45 100644 --- a/src/state/queries/messages/update-all-read.ts +++ b/src/state/queries/messages/update-all-read.ts @@ -1,8 +1,8 @@ -import {ChatBskyConvoListConvos} from '@atproto/api' +import {type ChatBskyConvoListConvos} from '@atproto/api' import {useMutation, useQueryClient} from '@tanstack/react-query' +import {DM_SERVICE_HEADERS} from '#/lib/constants' import {logger} from '#/logger' -import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const' import {useAgent} from '#/state/session' import {RQKEY as CONVO_LIST_KEY} from './list-conversations' diff --git a/src/state/queries/service.ts b/src/state/queries/service.ts index 6bfd0b011..e9661db9e 100644 --- a/src/state/queries/service.ts +++ b/src/state/queries/service.ts @@ -1,6 +1,7 @@ -import {BskyAgent} from '@atproto/api' import {useQuery} from '@tanstack/react-query' +import {Agent} from '../session/agent' + const RQKEY_ROOT = 'service' export const RQKEY = (serviceUrl: string) => [RQKEY_ROOT, serviceUrl] @@ -8,7 +9,7 @@ export function useServiceQuery(serviceUrl: string) { return useQuery({ queryKey: RQKEY(serviceUrl), queryFn: async () => { - const agent = new BskyAgent({service: serviceUrl}) + const agent = new Agent(null, {service: serviceUrl}) const res = await agent.com.atproto.server.describeServer() return res.data }, diff --git a/src/state/queries/trending/useGetSuggestedUsersQuery.ts b/src/state/queries/trending/useGetSuggestedUsersQuery.ts index 05cc4d74d..898029398 100644 --- a/src/state/queries/trending/useGetSuggestedUsersQuery.ts +++ b/src/state/queries/trending/useGetSuggestedUsersQuery.ts @@ -17,6 +17,7 @@ export type QueryProps = { category?: string | null limit?: number enabled?: boolean + overrideInterests?: string[] } export const getSuggestedUsersQueryKeyRoot = 'unspecced-suggested-users' @@ -24,6 +25,7 @@ export const createGetSuggestedUsersQueryKey = (props: QueryProps) => [ getSuggestedUsersQueryKeyRoot, props.category, props.limit, + props.overrideInterests?.join(','), ] export function useGetSuggestedUsersQuery(props: QueryProps) { @@ -36,6 +38,7 @@ export function useGetSuggestedUsersQuery(props: QueryProps) { queryKey: createGetSuggestedUsersQueryKey(props), queryFn: async () => { const contentLangs = getContentLanguages().join(',') + const interests = aggregateUserInterests(preferences) const {data} = await agent.app.bsky.unspecced.getSuggestedUsers( { category: props.category ?? undefined, @@ -43,7 +46,11 @@ export function useGetSuggestedUsersQuery(props: QueryProps) { }, { headers: { - ...createBskyTopicsHeader(aggregateUserInterests(preferences)), + ...createBskyTopicsHeader( + props.overrideInterests && props.overrideInterests.length > 0 + ? props.overrideInterests.join(',') + : interests, + ), 'Accept-Language': contentLangs, }, }, diff --git a/src/state/session/agent.ts b/src/state/session/agent.ts index 531e285ab..d063a09a2 100644 --- a/src/state/session/agent.ts +++ b/src/state/session/agent.ts @@ -1,8 +1,19 @@ -import {AtpSessionData, AtpSessionEvent, BskyAgent} from '@atproto/api' +import { + Agent as BaseAgent, + type AtprotoServiceType, + type AtpSessionData, + type AtpSessionEvent, + BskyAgent, + type Did, +} from '@atproto/api' +import {type FetchHandler} from '@atproto/api/dist/agent' +import {type SessionManager} from '@atproto/api/dist/session-manager' import {TID} from '@atproto/common-web' +import {type FetchHandlerOptions} from '@atproto/xrpc' import {networkRetry} from '#/lib/async/retry' import { + BLUESKY_PROXY_HEADER, BSKY_SERVICE, DISCOVER_SAVED_FEED, IS_PROD_SERVICE, @@ -19,12 +30,17 @@ import { configureModerationForAccount, configureModerationForGuest, } from './moderation' -import {SessionAccount} from './types' +import {type SessionAccount} from './types' import {isSessionExpired, isSignupQueued} from './util' +export type ProxyHeaderValue = `${Did}#${AtprotoServiceType}` + export function createPublicAgent() { configureModerationForGuest() // Side effect but only relevant for tests - return new BskyAppAgent({service: PUBLIC_BSKY_SERVICE}) + + const agent = new BskyAppAgent({service: PUBLIC_BSKY_SERVICE}) + agent.configureProxy(BLUESKY_PROXY_HEADER) + return agent } export async function createAgentAndResume( @@ -61,6 +77,8 @@ export async function createAgentAndResume( } } + agent.configureProxy(BLUESKY_PROXY_HEADER) + return agent.prepare(gates, moderation, onSessionChange) } @@ -93,6 +111,9 @@ export async function createAgentAndLogin( const account = agentToSessionAccountOrThrow(agent) const gates = tryFetchGates(account.did, 'prefer-fresh-gates') const moderation = configureModerationForAccount(agent, account) + + agent.configureProxy(BLUESKY_PROXY_HEADER) + return agent.prepare(gates, moderation, onSessionChange) } @@ -180,6 +201,8 @@ export async function createAgentAndCreateAccount( logger.error(e, {message: `session: failed snoozeEmailConfirmationPrompt`}) } + agent.configureProxy(BLUESKY_PROXY_HEADER) + return agent.prepare(gates, moderation, onSessionChange) } @@ -234,7 +257,22 @@ export function sessionAccountToSession( } } +export class Agent extends BaseAgent { + constructor( + proxyHeader: ProxyHeaderValue | null, + options: SessionManager | FetchHandler | FetchHandlerOptions, + ) { + super(options) + if (proxyHeader) { + this.configureProxy(proxyHeader) + } + } +} + // Not exported. Use factories above to create it. +// WARN: In the factories above, we _manually set a proxy header_ for the agent after we do whatever it is we are supposed to do. +// Ideally, we wouldn't be doing this. However, since there is so much logic that requires making calls to the PDS right now, it +// feels safer to just let those run as-is and set the header afterward. let realFetch = globalThis.fetch class BskyAppAgent extends BskyAgent { persistSessionHandler: ((event: AtpSessionEvent) => void) | undefined = diff --git a/src/state/unstable-post-source.tsx b/src/state/unstable-post-source.tsx index 450f2c120..17fe18840 100644 --- a/src/state/unstable-post-source.tsx +++ b/src/state/unstable-post-source.tsx @@ -2,7 +2,7 @@ import {useEffect, useId, useState} from 'react' import {type AppBskyFeedDefs, AtUri} from '@atproto/api' import {Logger} from '#/logger' -import {type FeedDescriptor} from '#/state/queries/post-feed' +import {type FeedSourceInfo} from '#/state/queries/feed' /** * Separate logger for better debugging @@ -11,7 +11,7 @@ const logger = Logger.create(Logger.Context.PostSource) export type PostSource = { post: AppBskyFeedDefs.FeedViewPost - feed?: FeedDescriptor + feedSourceInfo?: FeedSourceInfo } /** |