···1616# Enable debug logs for specific logger instances
1717EXPO_PUBLIC_LOG_DEBUG=session
18181919+# Bluesky appview DID
2020+EXPO_PUBLIC_BLUESKY_PROXY_DID=
2121+1922# Chat service DID
2023EXPO_PUBLIC_CHAT_PROXY_DID=
2124
+6
src/env/common.ts
···6363export const LOG_DEBUG: string = process.env.EXPO_PUBLIC_LOG_DEBUG || ''
64646565/**
6666+ * The DID of the Bluesky appview to proxy to
6767+ */
6868+export const BLUESKY_PROXY_DID: Did =
6969+ process.env.EXPO_PUBLIC_BLUESKY_PROXY_DID || 'did:web:api.bsky.app'
7070+7171+/**
6672 * The DID of the chat service to proxy to
6773 */
6874export const CHAT_PROXY_DID: Did =
···11import React, {useState} from 'react'
22import {ActivityIndicator, Keyboard, View} from 'react-native'
33-import {ComAtprotoServerDescribeServer} from '@atproto/api'
44-import {BskyAgent} from '@atproto/api'
33+import {type ComAtprotoServerDescribeServer} from '@atproto/api'
54import {msg, Trans} from '@lingui/macro'
65import {useLingui} from '@lingui/react'
76import * as EmailValidator from 'email-validator'
···98import {isNetworkError} from '#/lib/strings/errors'
109import {cleanError} from '#/lib/strings/errors'
1110import {logger} from '#/logger'
1111+import {Agent} from '#/state/session/agent'
1212import {atoms as a, useTheme} from '#/alf'
1313import {Button, ButtonText} from '#/components/Button'
1414import {FormError} from '#/components/forms/FormError'
···5555 setIsProcessing(true)
56565757 try {
5858- const agent = new BskyAgent({service: serviceUrl})
5858+ const agent = new Agent(null, {service: serviceUrl})
5959 await agent.com.atproto.server.requestPasswordReset({email})
6060 onEmailSent()
6161 } catch (e: any) {
+2-2
src/screens/Login/SetNewPasswordForm.tsx
···11import {useState} from 'react'
22import {ActivityIndicator, View} from 'react-native'
33-import {BskyAgent} from '@atproto/api'
43import {msg, Trans} from '@lingui/macro'
54import {useLingui} from '@lingui/react'
65···98import {cleanError} from '#/lib/strings/errors'
109import {checkAndFormatResetCode} from '#/lib/strings/password'
1110import {logger} from '#/logger'
1111+import {Agent} from '#/state/session/agent'
1212import {atoms as a, useTheme} from '#/alf'
1313import {Button, ButtonText} from '#/components/Button'
1414import {FormError} from '#/components/forms/FormError'
···6363 setIsProcessing(true)
64646565 try {
6666- const agent = new BskyAgent({service: serviceUrl})
6666+ const agent = new Agent(null, {service: serviceUrl})
6767 await agent.com.atproto.server.resetPassword({
6868 token: formattedCode,
6969 password,
+1-1
src/state/messages/convo/agent.ts
···1010import {nanoid} from 'nanoid/non-secure'
11111212import {networkRetry} from '#/lib/async/retry'
1313+import {DM_SERVICE_HEADERS} from '#/lib/constants'
1314import {isNetworkError} from '#/lib/strings/errors'
1415import {Logger} from '#/logger'
1516import {isNative} from '#/platform/detection'
···3334} from '#/state/messages/convo/types'
3435import {type MessagesEventBus} from '#/state/messages/events/agent'
3536import {type MessagesEventBusError} from '#/state/messages/events/types'
3636-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
37373838const logger = Logger.create(Logger.Context.ConversationAgent)
3939
+1-1
src/state/messages/events/agent.ts
···33import {nanoid} from 'nanoid/non-secure'
4455import {networkRetry} from '#/lib/async/retry'
66+import {DM_SERVICE_HEADERS} from '#/lib/constants'
67import {isNetworkError} from '#/lib/strings/errors'
78import {Logger} from '#/logger'
89import {
···1718 type MessagesEventBusParams,
1819 MessagesEventBusStatus,
1920} from '#/state/messages/events/types'
2020-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
21212222const logger = Logger.create(Logger.Context.DMsAgent)
2323
+4-3
src/state/queries/handle-availability.ts
···11-import {Agent, ComAtprotoTempCheckHandleAvailability} from '@atproto/api'
11+import {ComAtprotoTempCheckHandleAvailability} from '@atproto/api'
22import {useQuery} from '@tanstack/react-query'
3344import {
···1010import {logger} from '#/logger'
1111import {useDebouncedValue} from '#/components/live/utils'
1212import * as bsky from '#/types/bsky'
1313+import {Agent} from '../session/agent'
13141415export const RQKEY_handleAvailability = (
1516 handle: string,
···7475 },
7576) {
7677 if (serviceDid === BSKY_SERVICE_DID) {
7777- const agent = new Agent({service: BSKY_SERVICE})
7878+ const agent = new Agent(null, {service: BSKY_SERVICE})
7879 // entryway has a special API for handle availability
7980 const {data} = await agent.com.atproto.temp.checkHandleAvailability({
8081 handle,
···109110 }
110111 } else {
111112 // 3rd party PDSes won't have this API so just try and resolve the handle
112112- const agent = new Agent({service: PUBLIC_BSKY_SERVICE})
113113+ const agent = new Agent(null, {service: PUBLIC_BSKY_SERVICE})
113114 try {
114115 const res = await agent.resolveHandle({
115116 handle,
+5-2
src/state/queries/messages/accept-conversation.ts
···11-import {ChatBskyConvoAcceptConvo, ChatBskyConvoListConvos} from '@atproto/api'
11+import {
22+ type ChatBskyConvoAcceptConvo,
33+ type ChatBskyConvoListConvos,
44+} from '@atproto/api'
25import {useMutation, useQueryClient} from '@tanstack/react-query'
3677+import {DM_SERVICE_HEADERS} from '#/lib/constants'
48import {logger} from '#/logger'
59import {useAgent} from '#/state/session'
66-import {DM_SERVICE_HEADERS} from './const'
710import {
811 RQKEY as CONVO_LIST_KEY,
912 RQKEY_ROOT as CONVO_LIST_ROOT_KEY,
···11import {useQuery} from '@tanstack/react-query'
2233-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
33+import {DM_SERVICE_HEADERS} from '#/lib/constants'
44import {useAgent} from '#/state/session'
55import {STALE} from '..'
66
···11-import {ChatBskyConvoGetConvoForMembers} from '@atproto/api'
11+import {type ChatBskyConvoGetConvoForMembers} from '@atproto/api'
22import {useMutation, useQueryClient} from '@tanstack/react-query'
3344+import {DM_SERVICE_HEADERS} from '#/lib/constants'
45import {logger} from '#/logger'
55-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
66import {useAgent} from '#/state/session'
77import {precacheConvoQuery} from './conversation'
88
+5-2
src/state/queries/messages/leave-conversation.ts
···11import {useMemo} from 'react'
22-import {ChatBskyConvoLeaveConvo, ChatBskyConvoListConvos} from '@atproto/api'
22+import {
33+ type ChatBskyConvoLeaveConvo,
44+ type ChatBskyConvoListConvos,
55+} from '@atproto/api'
36import {
47 useMutation,
58 useMutationState,
69 useQueryClient,
710} from '@tanstack/react-query'
8111212+import {DM_SERVICE_HEADERS} from '#/lib/constants'
913import {logger} from '#/logger'
1010-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
1114import {useAgent} from '#/state/session'
1215import {RQKEY_ROOT as CONVO_LIST_KEY} from './list-conversations'
1316
+1-1
src/state/queries/messages/list-conversations.tsx
···1313} from '@tanstack/react-query'
1414import throttle from 'lodash.throttle'
15151616+import {DM_SERVICE_HEADERS} from '#/lib/constants'
1617import {useCurrentConvoId} from '#/state/messages/current-convo-id'
1718import {useMessagesEventBus} from '#/state/messages/events'
1819import {useModerationOpts} from '#/state/preferences/moderation-opts'
1919-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
2020import {useAgent, useSession} from '#/state/session'
2121import {useLeftConvos} from './leave-conversation'
2222
+9-5
src/state/queries/messages/mute-conversation.ts
···11import {
22- ChatBskyConvoDefs,
33- ChatBskyConvoListConvos,
44- ChatBskyConvoMuteConvo,
22+ type ChatBskyConvoDefs,
33+ type ChatBskyConvoListConvos,
44+ type ChatBskyConvoMuteConvo,
55} from '@atproto/api'
66-import {InfiniteData, useMutation, useQueryClient} from '@tanstack/react-query'
66+import {
77+ type InfiniteData,
88+ useMutation,
99+ useQueryClient,
1010+} from '@tanstack/react-query'
71188-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
1212+import {DM_SERVICE_HEADERS} from '#/lib/constants'
913import {useAgent} from '#/state/session'
1014import {RQKEY as CONVO_KEY} from './conversation'
1115import {RQKEY_ROOT as CONVO_LIST_KEY} from './list-conversations'
+2-2
src/state/queries/messages/update-all-read.ts
···11-import {ChatBskyConvoListConvos} from '@atproto/api'
11+import {type ChatBskyConvoListConvos} from '@atproto/api'
22import {useMutation, useQueryClient} from '@tanstack/react-query'
3344+import {DM_SERVICE_HEADERS} from '#/lib/constants'
45import {logger} from '#/logger'
55-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
66import {useAgent} from '#/state/session'
77import {RQKEY as CONVO_LIST_KEY} from './list-conversations'
88
···11-import {AtpSessionData, AtpSessionEvent, BskyAgent} from '@atproto/api'
11+import {
22+ Agent as BaseAgent,
33+ type AtprotoServiceType,
44+ type AtpSessionData,
55+ type AtpSessionEvent,
66+ BskyAgent,
77+ type Did,
88+} from '@atproto/api'
99+import {type FetchHandler} from '@atproto/api/dist/agent'
1010+import {type SessionManager} from '@atproto/api/dist/session-manager'
211import {TID} from '@atproto/common-web'
1212+import {type FetchHandlerOptions} from '@atproto/xrpc'
313414import {networkRetry} from '#/lib/async/retry'
515import {
1616+ BLUESKY_PROXY_HEADER,
617 BSKY_SERVICE,
718 DISCOVER_SAVED_FEED,
819 IS_PROD_SERVICE,
···1930 configureModerationForAccount,
2031 configureModerationForGuest,
2132} from './moderation'
2222-import {SessionAccount} from './types'
3333+import {type SessionAccount} from './types'
2334import {isSessionExpired, isSignupQueued} from './util'
24353636+export type ProxyHeaderValue = `${Did}#${AtprotoServiceType}`
3737+2538export function createPublicAgent() {
2639 configureModerationForGuest() // Side effect but only relevant for tests
2727- return new BskyAppAgent({service: PUBLIC_BSKY_SERVICE})
4040+4141+ const agent = new BskyAppAgent({service: PUBLIC_BSKY_SERVICE})
4242+ agent.configureProxy(BLUESKY_PROXY_HEADER)
4343+ return agent
2844}
29453046export async function createAgentAndResume(
···6177 }
6278 }
63798080+ agent.configureProxy(BLUESKY_PROXY_HEADER)
8181+6482 return agent.prepare(gates, moderation, onSessionChange)
6583}
6684···93111 const account = agentToSessionAccountOrThrow(agent)
94112 const gates = tryFetchGates(account.did, 'prefer-fresh-gates')
95113 const moderation = configureModerationForAccount(agent, account)
114114+115115+ agent.configureProxy(BLUESKY_PROXY_HEADER)
116116+96117 return agent.prepare(gates, moderation, onSessionChange)
97118}
98119···180201 logger.error(e, {message: `session: failed snoozeEmailConfirmationPrompt`})
181202 }
182203204204+ agent.configureProxy(BLUESKY_PROXY_HEADER)
205205+183206 return agent.prepare(gates, moderation, onSessionChange)
184207}
185208···234257 }
235258}
236259260260+export class Agent extends BaseAgent {
261261+ constructor(
262262+ proxyHeader: ProxyHeaderValue | null,
263263+ options: SessionManager | FetchHandler | FetchHandlerOptions,
264264+ ) {
265265+ super(options)
266266+ if (proxyHeader) {
267267+ this.configureProxy(proxyHeader)
268268+ }
269269+ }
270270+}
271271+237272// Not exported. Use factories above to create it.
273273+// 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.
274274+// Ideally, we wouldn't be doing this. However, since there is so much logic that requires making calls to the PDS right now, it
275275+// feels safer to just let those run as-is and set the header afterward.
238276let realFetch = globalThis.fetch
239277class BskyAppAgent extends BskyAgent {
240278 persistSessionHandler: ((event: AtpSessionEvent) => void) | undefined =
+1-1
src/view/com/modals/DeleteAccount.tsx
···1010import {msg, Trans} from '@lingui/macro'
1111import {useLingui} from '@lingui/react'
12121313+import {DM_SERVICE_HEADERS} from '#/lib/constants'
1314import {usePalette} from '#/lib/hooks/usePalette'
1415import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
1516import {cleanError} from '#/lib/strings/errors'
···1718import {useTheme} from '#/lib/ThemeContext'
1819import {isAndroid, isWeb} from '#/platform/detection'
1920import {useModalControls} from '#/state/modals'
2020-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
2121import {useAgent, useSession, useSessionApi} from '#/state/session'
2222import {atoms as a, useTheme as useNewTheme} from '#/alf'
2323import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
···3131import {useQueryClient} from '@tanstack/react-query'
32323333import {MAX_POST_LINES} from '#/lib/constants'
3434+import {DM_SERVICE_HEADERS} from '#/lib/constants'
3435import {useAnimatedValue} from '#/lib/hooks/useAnimatedValue'
3536import {usePalette} from '#/lib/hooks/usePalette'
3637import {makeProfileLink} from '#/lib/routes/links'
···4142import {niceDate} from '#/lib/strings/time'
4243import {s} from '#/lib/styles'
4344import {logger} from '#/logger'
4444-import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
4545import {type FeedNotification} from '#/state/queries/notifications/feed'
4646import {unstableCacheProfileView} from '#/state/queries/unstable-profile-cache'
4747import {useAgent} from '#/state/session'