Bluesky app fork with some witchin' additions 💫

revert pdsAgent commits & remove custom AppView support

Bye bye "fix: ensure `com.atproto.*` calls go through without proxying" "add deer custom-appview" "unproxy preferences" (ALSO removes the pdsAgent import added in "couple code error fixes" 3814f6b)

This reverts commits 69cf6f93b829d1d25e5fa37875d90070f68ef2ed, 6b305f2626cffa73b1989dec44a071ae7b4ba2b9, and 45584b9c28a5b657e3684b2d8f3cbea06668c116.

xan.lol cccfbd0b cb54cd87

verified
+99 -379
+16 -10
src/components/PostControls/PostMenu/PostMenuItems.tsx
··· 17 17 type AppBskyFeedThreadgate, 18 18 AtUri, 19 19 type BlobRef, 20 - isDid, 21 20 type RichText as RichTextAPI, 22 21 } from '@atproto/api' 23 22 import {msg} from '@lingui/macro' ··· 44 43 import {type Shadow} from '#/state/cache/post-shadow' 45 44 import {useProfileShadow} from '#/state/cache/profile-shadow' 46 45 import {useFeedFeedbackContext} from '#/state/feed-feedback' 47 - import {useLanguagePrefs} from '#/state/preferences' 48 - import {useHiddenPosts, useHiddenPostsApi} from '#/state/preferences' 46 + import { 47 + useHiddenPosts, 48 + useHiddenPostsApi, 49 + useLanguagePrefs, 50 + } from '#/state/preferences' 49 51 import {usePinnedPostMutation} from '#/state/queries/pinned-post' 50 52 import { 51 53 usePostDeleteMutation, ··· 58 60 useProfileMuteMutationQueue, 59 61 } from '#/state/queries/profile' 60 62 import {resolvePdsServiceUrl} from '#/state/queries/resolve-identity' 61 - import {useToggleReplyVisibilityMutation} from '#/state/queries/threadgate' 62 63 import { 63 64 InvalidInteractionSettingsError, 64 65 MAX_HIDDEN_REPLIES, 65 66 MaxHiddenRepliesError, 67 + useToggleReplyVisibilityMutation, 66 68 } from '#/state/queries/threadgate' 67 69 import {useRequireAuth, useSession} from '#/state/session' 68 70 import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies' ··· 84 86 import {Eye_Stroke2_Corner0_Rounded as Eye} from '#/components/icons/Eye' 85 87 import {EyeSlash_Stroke2_Corner0_Rounded as EyeSlash} from '#/components/icons/EyeSlash' 86 88 import {Filter_Stroke2_Corner0_Rounded as Filter} from '#/components/icons/Filter' 87 - import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute' 88 - import {Mute_Stroke2_Corner0_Rounded as Mute} from '#/components/icons/Mute' 89 + import { 90 + Mute_Stroke2_Corner0_Rounded as Mute, 91 + Mute_Stroke2_Corner0_Rounded as MuteIcon, 92 + } from '#/components/icons/Mute' 89 93 import {Pencil_Stroke2_Corner0_Rounded as Pen} from '#/components/icons/Pencil' 90 94 import {PersonX_Stroke2_Corner0_Rounded as PersonX} from '#/components/icons/Person' 91 95 import {Pin_Stroke2_Corner0_Rounded as PinIcon} from '#/components/icons/Pin' 92 96 import {SettingsGear2_Stroke2_Corner0_Rounded as Gear} from '#/components/icons/SettingsGear2' 93 - import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker' 94 - import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute} from '#/components/icons/Speaker' 97 + import { 98 + SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute, 99 + SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon, 100 + } from '#/components/icons/Speaker' 95 101 import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash' 96 102 import {Warning_Stroke2_Corner0_Rounded as Warning} from '#/components/icons/Warning' 97 103 import {Loader} from '#/components/Loader' ··· 603 609 if (!videoEmbed) return 604 610 const did = post.author.did 605 611 const cid = videoEmbed.cid 606 - if (!isDid(did)) return 607 - const pdsUrl = await resolvePdsServiceUrl(did as `did:${string}:${string}`) 612 + if (!did.startsWith('did:')) return 613 + const pdsUrl = await resolvePdsServiceUrl(did as `did:${string}`) 608 614 const uri = `${pdsUrl}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${cid}` 609 615 610 616 Toast.show(_(msg({message: 'Downloading video...', context: 'toast'})))
+1 -2
src/components/dialogs/EmailDialog/data/useConfirmEmail.ts
··· 1 1 import {useMutation} from '@tanstack/react-query' 2 2 3 3 import {useAgent, useSession} from '#/state/session' 4 - import {pdsAgent} from '#/state/session/agent' 5 4 6 5 export function useConfirmEmail({ 7 6 onSuccess, ··· 16 15 throw new Error('No email found for the current account') 17 16 } 18 17 19 - await pdsAgent(agent).com.atproto.server.confirmEmail({ 18 + await agent.com.atproto.server.confirmEmail({ 20 19 email: currentAccount.email.trim(), 21 20 token: token.trim(), 22 21 })
+1 -2
src/components/dialogs/EmailDialog/data/useManageEmail2FA.ts
··· 1 1 import {useMutation} from '@tanstack/react-query' 2 2 3 3 import {useAgent, useSession} from '#/state/session' 4 - import {pdsAgent} from '#/state/session/agent' 5 4 6 5 export function useManageEmail2FA() { 7 6 const agent = useAgent() ··· 18 17 throw new Error('No email found for the current account') 19 18 } 20 19 21 - await pdsAgent(agent).com.atproto.server.updateEmail({ 20 + await agent.com.atproto.server.updateEmail({ 22 21 email: currentAccount.email, 23 22 emailAuthFactor: enabled, 24 23 token,
+1 -3
src/components/dialogs/EmailDialog/data/useRequestEmailUpdate.ts
··· 1 1 import {useMutation} from '@tanstack/react-query' 2 2 3 3 import {useAgent} from '#/state/session' 4 - import {pdsAgent} from '#/state/session/agent' 5 4 6 5 export function useRequestEmailUpdate() { 7 6 const agent = useAgent() 8 7 9 8 return useMutation({ 10 9 mutationFn: async () => { 11 - return (await pdsAgent(agent).com.atproto.server.requestEmailUpdate()) 12 - .data 10 + return (await agent.com.atproto.server.requestEmailUpdate()).data 13 11 }, 14 12 }) 15 13 }
+1 -2
src/components/dialogs/EmailDialog/data/useRequestEmailVerification.ts
··· 1 1 import {useMutation} from '@tanstack/react-query' 2 2 3 3 import {useAgent} from '#/state/session' 4 - import {pdsAgent} from '#/state/session/agent' 5 4 6 5 export function useRequestEmailVerification() { 7 6 const agent = useAgent() 8 7 9 8 return useMutation({ 10 9 mutationFn: async () => { 11 - await pdsAgent(agent).com.atproto.server.requestEmailConfirmation() 10 + await agent.com.atproto.server.requestEmailConfirmation() 12 11 }, 13 12 }) 14 13 }
+1 -5
src/components/dialogs/EmailDialog/data/useUpdateEmail.ts
··· 1 1 import {useMutation} from '@tanstack/react-query' 2 2 3 3 import {useAgent} from '#/state/session' 4 - import {pdsAgent} from '#/state/session/agent' 5 4 import {useRequestEmailUpdate} from '#/components/dialogs/EmailDialog/data/useRequestEmailUpdate' 6 5 7 6 async function updateEmailAndRefreshSession( ··· 9 8 email: string, 10 9 token?: string, 11 10 ) { 12 - await pdsAgent(agent).com.atproto.server.updateEmail({ 13 - email: email.trim(), 14 - token, 15 - }) 11 + await agent.com.atproto.server.updateEmail({email: email.trim(), token}) 16 12 await agent.resumeSession(agent.session!) 17 13 } 18 14
+1 -2
src/components/intents/VerifyEmailIntentDialog.tsx
··· 4 4 import {useLingui} from '@lingui/react' 5 5 6 6 import {useAgent, useSession} from '#/state/session' 7 - import {pdsAgent} from '#/state/session/agent' 8 7 import {atoms as a, useBreakpoints, useTheme} from '#/alf' 9 8 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 10 9 import * as Dialog from '#/components/Dialog' ··· 52 51 53 52 const onPressResendEmail = async () => { 54 53 setSending(true) 55 - await pdsAgent(agent).com.atproto.server.requestEmailConfirmation() 54 + await agent.com.atproto.server.requestEmailConfirmation() 56 55 setSending(false) 57 56 setStatus('resent') 58 57 }
+3 -4
src/components/live/queries.ts
··· 16 16 import {updateProfileShadow} from '#/state/cache/profile-shadow' 17 17 import {useLiveNowConfig} from '#/state/service-config' 18 18 import {useAgent, useSession} from '#/state/session' 19 - import {pdsAgent} from '#/state/session/agent' 20 19 import * as Toast from '#/view/com/util/Toast' 21 20 import {useDialogContext} from '#/components/Dialog' 22 21 import {getLiveServiceNames} from '#/components/live/utils' ··· 110 109 const repo = currentAccount.did 111 110 const collection = 'app.bsky.actor.status' 112 111 113 - const existing = await pdsAgent(agent) 114 - .com.atproto.repo.getRecord({repo, collection, rkey: 'self'}) 112 + const existing = await agent.com.atproto.repo 113 + .getRecord({repo, collection, rkey: 'self'}) 115 114 .catch(_e => undefined) 116 115 117 - await pdsAgent(agent).com.atproto.repo.putRecord({ 116 + await agent.com.atproto.repo.putRecord({ 118 117 repo, 119 118 collection, 120 119 rkey: 'self',
-10
src/env/common.ts
··· 118 118 * URLs for the live-event config web worker. Can be a 119 119 * locally running server, see `env.example` for more. 120 120 */ 121 - export const LIVE_EVENTS_DEV_URL = process.env.LIVE_EVENTS_DEV_URL 122 - export const LIVE_EVENTS_PROD_URL = `https://live-events.workers.bsky.app` 123 - export const LIVE_EVENTS_URL = IS_DEV 124 - ? (LIVE_EVENTS_DEV_URL ?? LIVE_EVENTS_PROD_URL) 125 - : LIVE_EVENTS_PROD_URL 126 - 127 - export const ENV_PUBLIC_BSKY_SERVICE: string | undefined = 128 - process.env.EXPO_PUBLIC_PUBLIC_BSKY_SERVICE 129 - export const ENV_APPVIEW_DID_PROXY: `did:${string}:${string}#bsky_appview` | undefined = 130 - process.env.EXPO_PUBLIC_APPVIEW_DID_PROXY
+2 -3
src/lib/api/feed/custom.ts
··· 5 5 jsonStringToLex, 6 6 } from '@atproto/api' 7 7 8 - import {PUBLIC_BSKY_SERVICE} from '#/lib/constants' 9 8 import { 10 9 getAppLanguageAsContentLanguage, 11 10 getContentLanguages, ··· 121 120 122 121 // manually construct fetch call so we can add the `lang` cache-busting param 123 122 let res = await fetch( 124 - `${PUBLIC_BSKY_SERVICE}/xrpc/app.bsky.feed.getFeed?feed=${feed}${ 123 + `https://api.bsky.app/xrpc/app.bsky.feed.getFeed?feed=${feed}${ 125 124 cursor ? `&cursor=${cursor}` : '' 126 125 }&limit=${limit}&lang=${contentLangs}`, 127 126 { ··· 141 140 142 141 // no data, try again with language headers removed 143 142 res = await fetch( 144 - `${PUBLIC_BSKY_SERVICE}/xrpc/app.bsky.feed.getFeed?feed=${feed}${ 143 + `https://api.bsky.app/xrpc/app.bsky.feed.getFeed?feed=${feed}${ 145 144 cursor ? `&cursor=${cursor}` : '' 146 145 }&limit=${limit}`, 147 146 {method: 'GET', headers: {'Accept-Language': '', ...labelersHeader}},
+12 -5
src/lib/api/index.ts
··· 23 23 import * as Hasher from 'multiformats/hashes/hasher' 24 24 25 25 import {isNetworkError} from '#/lib/strings/errors' 26 - import {parseMarkdownLinks,shortenLinks, stripInvalidMentions} from '#/lib/strings/rich-text-manip' 26 + import { 27 + parseMarkdownLinks, 28 + shortenLinks, 29 + stripInvalidMentions, 30 + } from '#/lib/strings/rich-text-manip' 27 31 import {logger} from '#/logger' 28 32 import {compressImage} from '#/state/gallery' 29 33 import { ··· 34 38 createThreadgateRecord, 35 39 threadgateAllowUISettingToAllowRecordValue, 36 40 } from '#/state/queries/threadgate' 37 - import {pdsAgent} from '#/state/session/agent' 38 41 import { 39 42 type EmbedDraft, 40 43 type PostDraft, ··· 173 176 } 174 177 175 178 try { 176 - await pdsAgent(agent).com.atproto.repo.applyWrites({ 179 + await agent.com.atproto.repo.applyWrites({ 177 180 repo: agent.assertDid, 178 181 writes: writes, 179 182 validate: true, ··· 370 373 371 374 const width = Math.round( 372 375 videoDraft.asset?.width || 373 - ('redraftDimensions' in videoDraft ? videoDraft.redraftDimensions.width : 1000) 376 + ('redraftDimensions' in videoDraft 377 + ? videoDraft.redraftDimensions.width 378 + : 1000), 374 379 ) 375 380 const height = Math.round( 376 381 videoDraft.asset?.height || 377 - ('redraftDimensions' in videoDraft ? videoDraft.redraftDimensions.height : 1000) 382 + ('redraftDimensions' in videoDraft 383 + ? videoDraft.redraftDimensions.height 384 + : 1000), 378 385 ) 379 386 380 387 // aspect ratio values must be >0 - better to leave as unset otherwise
+2 -4
src/lib/constants.ts
··· 3 3 4 4 import {type ProxyHeaderValue} from '#/state/session/agent' 5 5 import {BLUESKY_PROXY_DID, CHAT_PROXY_DID} from '#/env' 6 - import {ENV_APPVIEW_DID_PROXY, ENV_PUBLIC_BSKY_SERVICE} from '#/env' 6 + 7 7 export const LOCAL_DEV_SERVICE = 8 8 Platform.OS === 'android' ? 'http://10.0.2.2:2583' : 'http://localhost:2583' 9 9 export const STAGING_SERVICE = 'https://staging.bsky.dev' 10 10 export const BSKY_SERVICE = 'https://bsky.social' 11 11 export const BSKY_SERVICE_DID = 'did:web:bsky.social' 12 - export const PUBLIC_BSKY_SERVICE = 13 - ENV_PUBLIC_BSKY_SERVICE || 'https://public.api.bsky.app' 12 + export const PUBLIC_BSKY_SERVICE = 'https://public.api.bsky.app' 14 13 export const DEFAULT_SERVICE = BSKY_SERVICE 15 14 export const HELP_DESK_URL = `https://tangled.org/jollywhoppers.com/witchsky.app/` 16 15 export const EMBED_SERVICE = 'https://embed.bsky.app' 17 16 export const EMBED_SCRIPT = `${EMBED_SERVICE}/static/embed.js` 18 17 export const BSKY_DOWNLOAD_URL = 'https://bsky.app/download' 19 - export const APPVIEW_DID_PROXY = ENV_APPVIEW_DID_PROXY 20 18 export const STARTER_PACK_MAX_SIZE = 150 21 19 export const CARD_ASPECT_RATIO = 1200 / 630 22 20
+1 -2
src/lib/generate-starterpack.ts
··· 15 15 import {sanitizeHandle} from '#/lib/strings/handles' 16 16 import {enforceLen} from '#/lib/strings/helpers' 17 17 import {useAgent} from '#/state/session' 18 - import {pdsAgent} from '#/state/session/agent' 19 18 import type * as bsky from '#/types/bsky' 20 19 21 20 export const createStarterPackList = async ({ ··· 45 44 }, 46 45 ) 47 46 if (!list) throw new Error('List creation failed') 48 - await pdsAgent(agent).com.atproto.repo.applyWrites({ 47 + await agent.com.atproto.repo.applyWrites({ 49 48 repo: agent.session!.did, 50 49 writes: profiles.map(p => createListItem({did: p.did, listUri: list.uri})), 51 50 })
+1 -4
src/lib/media/video/upload.shared.ts
··· 5 5 import {VIDEO_SERVICE_DID} from '#/lib/constants' 6 6 import {UploadLimitError} from '#/lib/media/video/errors' 7 7 import {getServiceAuthAudFromUrl} from '#/lib/strings/url-helpers' 8 - import {pdsAgent} from '#/state/session/agent' 9 8 import {createVideoAgent} from './util' 10 9 11 10 export async function getServiceAuthToken({ ··· 23 22 if (!pdsAud) { 24 23 throw new Error('Agent does not have a PDS URL') 25 24 } 26 - const {data: serviceAuth} = await pdsAgent( 27 - agent, 28 - ).com.atproto.server.getServiceAuth({ 25 + const {data: serviceAuth} = await agent.com.atproto.server.getServiceAuth({ 29 26 aud: aud ?? pdsAud, 30 27 lxm, 31 28 exp,
+1 -2
src/lib/react-query.tsx
··· 11 11 12 12 import {listenNetworkConfirmed, listenNetworkLost} from '#/state/events' 13 13 import {IS_NATIVE, IS_WEB} from '#/env' 14 - import {PUBLIC_BSKY_SERVICE} from './constants' 15 14 16 15 declare global { 17 16 interface Window { ··· 29 28 setTimeout(() => { 30 29 controller.abort() 31 30 }, 15e3) 32 - const res = await fetch(`${PUBLIC_BSKY_SERVICE}/xrpc/_health`, { 31 + const res = await fetch('https://public.api.bsky.app/xrpc/_health', { 33 32 cache: 'no-store', 34 33 signal: controller.signal, 35 34 })
+1 -2
src/screens/Deactivated.tsx
··· 13 13 useSession, 14 14 useSessionApi, 15 15 } from '#/state/session' 16 - import {pdsAgent} from '#/state/session/agent' 17 16 import {useLoggedOutViewControls} from '#/state/shell/logged-out' 18 17 import {Logo} from '#/view/icons/Logo' 19 18 import {atoms as a, useTheme} from '#/alf' ··· 70 69 const handleActivate = React.useCallback(async () => { 71 70 try { 72 71 setPending(true) 73 - await pdsAgent(agent).com.atproto.server.activateAccount() 72 + await agent.com.atproto.server.activateAccount() 74 73 await queryClient.resetQueries() 75 74 await agent.resumeSession(agent.session!) 76 75 } catch (e: any) {
+1 -2
src/screens/Onboarding/util.ts
··· 9 9 import chunk from 'lodash.chunk' 10 10 11 11 import {until} from '#/lib/async/until' 12 - import {pdsAgent} from '#/state/session/agent' 13 12 14 13 export async function bulkWriteFollows(agent: BskyAgent, dids: string[]) { 15 14 const session = agent.session ··· 36 35 37 36 const chunks = chunk(followWrites, 50) 38 37 for (const chunk of chunks) { 39 - await pdsAgent(agent).com.atproto.repo.applyWrites({ 38 + await agent.com.atproto.repo.applyWrites({ 40 39 repo: session.did, 41 40 writes: chunk, 42 41 })
+1 -157
src/screens/Settings/DeerSettings.tsx
··· 1 1 import {useState} from 'react' 2 2 import {View} from 'react-native' 3 - import {isDid} from '@atproto/api' 4 3 import {type ProfileViewBasic} from '@atproto/api/dist/client/types/app/bsky/actor/defs' 5 4 import {msg, Trans} from '@lingui/macro' 6 5 import {useLingui} from '@lingui/react' 7 6 import {type NativeStackScreenProps} from '@react-navigation/native-stack' 8 7 9 - import {APPVIEW_DID_PROXY} from '#/lib/constants' 10 8 import {usePalette} from '#/lib/hooks/usePalette' 11 9 import {type CommonNavigatorParams} from '#/lib/routes/types' 12 10 import {type Gate} from '#/lib/statsig/gates' ··· 21 19 useConstellationInstance, 22 20 useSetConstellationInstance, 23 21 } from '#/state/preferences/constellation-instance' 24 - import {useCustomAppViewDid} from '#/state/preferences/custom-appview-did' 25 22 import { 26 23 useDeerVerificationEnabled, 27 24 useDeerVerificationTrusted, ··· 113 110 useShowLinkInHandle, 114 111 } from '#/state/preferences/show-link-in-handle.tsx' 115 112 import {useProfilesQuery} from '#/state/queries/profile' 116 - import {findService, useDidDocument} from '#/state/queries/resolve-identity' 117 - import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' 118 113 import * as SettingsList from '#/screens/Settings/components/SettingsList' 119 114 import {atoms as a, useBreakpoints} from '#/alf' 120 115 import {Admonition} from '#/components/Admonition' ··· 133 128 import {Text} from '#/components/Typography' 134 129 import {IS_WEB} from '#/env' 135 130 import {SearchProfileCard} from '../Search/components/SearchProfileCard' 131 + 136 132 type Props = NativeStackScreenProps<CommonNavigatorParams> 137 133 138 134 const defaultGateValues = { ··· 229 225 ) 230 226 } 231 227 232 - function CustomAppViewDidDialog({ 233 - control, 234 - }: { 235 - control: Dialog.DialogControlProps 236 - }) { 237 - const pal = usePalette('default') 238 - const {_} = useLingui() 239 - 240 - const [did, setDid] = useState('') 241 - const [, setCustomAppViewDid] = useCustomAppViewDid() 242 - 243 - const doc = useDidDocument({did}) 244 - const bskyAppViewService = 245 - doc.data && findService(doc.data, '#bsky_appview', 'BskyAppView') 246 - 247 - const submit = () => { 248 - if (did.length === 0) { 249 - setCustomAppViewDid(undefined) 250 - control.close() 251 - return 252 - } 253 - if (!bskyAppViewService?.serviceEndpoint) return 254 - setCustomAppViewDid(did) 255 - control.close() 256 - } 257 - 258 - return ( 259 - <Dialog.Outer 260 - control={control} 261 - nativeOptions={{preventExpansion: true}} 262 - onClose={() => setDid('')}> 263 - <Dialog.Handle /> 264 - <Dialog.ScrollableInner label={_(msg`Custom AppView Proxy DID`)}> 265 - <View style={[a.gap_sm, a.pb_lg]}> 266 - <Text style={[a.text_2xl, a.font_bold]}> 267 - <Trans>Custom AppView Proxy DID</Trans> 268 - </Text> 269 - </View> 270 - 271 - <View style={a.gap_lg}> 272 - <Dialog.Input 273 - label="Text input field" 274 - autoFocus 275 - style={[styles.textInput, pal.border, pal.text]} 276 - onChangeText={value => { 277 - setDid(value) 278 - }} 279 - placeholder={ 280 - APPVIEW_DID_PROXY?.substring(0, APPVIEW_DID_PROXY.indexOf('#')) || 281 - `did:web:api.bsky.app` 282 - } 283 - placeholderTextColor={pal.colors.textLight} 284 - onSubmitEditing={submit} 285 - accessibilityHint={_( 286 - msg`Input the DID of the AppView to proxy requests through`, 287 - )} 288 - isInvalid={ 289 - !!did && !bskyAppViewService?.serviceEndpoint && !doc.isLoading 290 - } 291 - /> 292 - 293 - {did && !isDid(did) && ( 294 - <View> 295 - <ErrorMessage message={_(msg`must enter a DID`)} /> 296 - </View> 297 - )} 298 - 299 - {did && (did.includes('#') || did.includes('?')) && ( 300 - <View> 301 - <ErrorMessage message={_(msg`don't include the service id`)} /> 302 - </View> 303 - )} 304 - 305 - {doc.isError && ( 306 - <View> 307 - <ErrorMessage 308 - message={ 309 - doc.error.message || _(msg`document resolution failure`) 310 - } 311 - /> 312 - </View> 313 - )} 314 - 315 - {doc.data && 316 - !bskyAppViewService && 317 - (doc.data as {message?: string}).message && ( 318 - <View> 319 - <ErrorMessage 320 - message={(doc.data as {message: string}).message} 321 - /> 322 - </View> 323 - )} 324 - 325 - {doc.data && !bskyAppViewService && ( 326 - <View> 327 - <ErrorMessage 328 - message={_(msg`document doesn't contain #bsky_appview service`)} 329 - /> 330 - </View> 331 - )} 332 - 333 - {bskyAppViewService && ( 334 - <Text style={[a.text_sm, a.leading_snug]}> 335 - {JSON.stringify(bskyAppViewService, null, 2)} 336 - </Text> 337 - )} 338 - 339 - <View style={IS_WEB && [a.flex_row, a.justify_end]}> 340 - <Button 341 - label={_(msg`Save`)} 342 - size="large" 343 - onPress={submit} 344 - variant="solid" 345 - color={did.length > 0 ? 'primary' : 'secondary'} 346 - disabled={ 347 - did.length !== 0 && !bskyAppViewService?.serviceEndpoint 348 - }> 349 - <ButtonText> 350 - {did.length > 0 ? <Trans>Save</Trans> : <Trans>Reset</Trans>} 351 - </ButtonText> 352 - </Button> 353 - </View> 354 - </View> 355 - 356 - <Dialog.Close /> 357 - </Dialog.ScrollableInner> 358 - </Dialog.Outer> 359 - ) 360 - } 361 - 362 228 function TrustedVerifiersDialog({ 363 229 control, 364 230 }: { ··· 498 364 [gate]: value, 499 365 }) 500 366 } 501 - const [customAppViewDid] = useCustomAppViewDid() 502 - const setCustomAppViewDidControl = Dialog.useDialogControl() 503 367 504 368 return ( 505 369 <Layout.Screen> ··· 640 504 Constellation is used to supplement AppView responses for custom 641 505 verifications and nuclear block bypass, via backlinks. Current 642 506 instance: {constellationInstance} 643 - </Trans> 644 - </Admonition> 645 - </SettingsList.Item> 646 - 647 - <SettingsList.Item> 648 - <SettingsList.ItemIcon icon={StarIcon} /> 649 - <SettingsList.ItemText> 650 - <Trans>{`Custom AppView DID`}</Trans> 651 - </SettingsList.ItemText> 652 - <SettingsList.BadgeButton 653 - label={customAppViewDid ? _(msg`Set`) : _(msg`Change`)} 654 - onPress={() => setCustomAppViewDidControl.open()} 655 - /> 656 - </SettingsList.Item> 657 - <SettingsList.Item> 658 - <Admonition type="info" style={[a.flex_1]}> 659 - <Trans> 660 - Restart app after changing your AppView. 661 - {customAppViewDid && _(` Currently ${customAppViewDid}`)} 662 507 </Trans> 663 508 </Admonition> 664 509 </SettingsList.Item> ··· 1003 848 </SettingsList.Container> 1004 849 </Layout.Content> 1005 850 <ConstellationInstanceDialog control={setConstellationInstanceControl} /> 1006 - <CustomAppViewDidDialog control={setCustomAppViewDidControl} /> 1007 851 <TrustedVerifiersDialog control={setTrustedVerifiersDialogControl} /> 1008 852 </Layout.Screen> 1009 853 )
+2 -3
src/screens/Settings/components/ChangePasswordDialog.tsx
··· 8 8 import {checkAndFormatResetCode} from '#/lib/strings/password' 9 9 import {logger} from '#/logger' 10 10 import {useAgent, useSession} from '#/state/session' 11 - import {pdsAgent} from '#/state/session/agent' 12 11 import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' 13 12 import {android, atoms as a, web} from '#/alf' 14 13 import {Button, ButtonIcon, ButtonText} from '#/components/Button' ··· 85 84 setError('') 86 85 setIsProcessing(true) 87 86 try { 88 - await pdsAgent(agent).com.atproto.server.requestPasswordReset({ 87 + await agent.com.atproto.server.requestPasswordReset({ 89 88 email: currentAccount.email, 90 89 }) 91 90 setStage(Stages.ChangePassword) ··· 129 128 setError('') 130 129 setIsProcessing(true) 131 130 try { 132 - await pdsAgent(agent).com.atproto.server.resetPassword({ 131 + await agent.com.atproto.server.resetPassword({ 133 132 token: formattedCode, 134 133 password: newPassword, 135 134 })
+1 -2
src/screens/Settings/components/DeactivateAccountDialog.tsx
··· 5 5 6 6 import {logger} from '#/logger' 7 7 import {useAgent, useSessionApi} from '#/state/session' 8 - import {pdsAgent} from '#/state/session/agent' 9 8 import {atoms as a, useBreakpoints, useTheme} from '#/alf' 10 9 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 11 10 import {type DialogOuterProps} from '#/components/Dialog' ··· 43 42 const handleDeactivate = React.useCallback(async () => { 44 43 try { 45 44 setPending(true) 46 - await pdsAgent(agent).com.atproto.server.deactivateAccount({}) 45 + await agent.com.atproto.server.deactivateAccount({}) 47 46 control.close(() => { 48 47 logoutCurrentAccount('Deactivated') 49 48 })
+3 -4
src/screens/Settings/components/DisableEmail2FADialog.tsx
··· 5 5 6 6 import {cleanError} from '#/lib/strings/errors' 7 7 import {useAgent, useSession} from '#/state/session' 8 - import {pdsAgent} from '#/state/session/agent' 9 8 import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' 10 9 import * as Toast from '#/view/com/util/Toast' 11 10 import {atoms as a, useBreakpoints, useTheme} from '#/alf' ··· 42 41 setError('') 43 42 setIsProcessing(true) 44 43 try { 45 - await pdsAgent(agent).com.atproto.server.requestEmailUpdate() 44 + await agent.com.atproto.server.requestEmailUpdate() 46 45 setStage(Stages.ConfirmCode) 47 46 } catch (e) { 48 47 setError(cleanError(String(e))) ··· 56 55 setIsProcessing(true) 57 56 try { 58 57 if (currentAccount?.email) { 59 - await pdsAgent(agent).com.atproto.server.updateEmail({ 60 - email: currentAccount!.email, 58 + await agent.com.atproto.server.updateEmail({ 59 + email: currentAccount.email, 61 60 token: confirmationCode.trim(), 62 61 emailAuthFactor: false, 63 62 })
+1 -2
src/screens/Settings/components/ExportCarDialog.tsx
··· 6 6 import {saveBytesToDisk} from '#/lib/media/manip' 7 7 import {logger} from '#/logger' 8 8 import {useAgent} from '#/state/session' 9 - import {pdsAgent} from '#/state/session/agent' 10 9 import {atoms as a, useTheme, web} from '#/alf' 11 10 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 12 11 import * as Dialog from '#/components/Dialog' ··· 33 32 try { 34 33 setLoading(true) 35 34 const did = agent.session.did 36 - const downloadRes = await pdsAgent(agent).com.atproto.sync.getRepo({did}) 35 + const downloadRes = await agent.com.atproto.sync.getRepo({did}) 37 36 const saveRes = await saveBytesToDisk( 38 37 'repo.car', 39 38 downloadRes.data,
+1 -2
src/screens/SignupQueued.tsx
··· 7 7 8 8 import {logger} from '#/logger' 9 9 import {isSignupQueued, useAgent, useSessionApi} from '#/state/session' 10 - import {pdsAgent} from '#/state/session/agent' 11 10 import {useOnboardingDispatch} from '#/state/shell' 12 11 import {Logo} from '#/view/icons/Logo' 13 12 import {atoms as a, native, useBreakpoints, useTheme, web} from '#/alf' ··· 38 37 const checkStatus = React.useCallback(async () => { 39 38 setProcessing(true) 40 39 try { 41 - const res = await pdsAgent(agent).com.atproto.temp.checkSignupQueue() 40 + const res = await agent.com.atproto.temp.checkSignupQueue() 42 41 if (res.data.activated) { 43 42 // ready to go, exchange the access token for a usable one and kick off onboarding 44 43 await agent.sessionManager.refreshSession()
-21
src/state/preferences/custom-appview-did.tsx
··· 1 - import {isDid} from '@atproto/api' 2 - 3 - import {device, useStorage} from '#/storage' 4 - 5 - export function useCustomAppViewDid() { 6 - const [customAppViewDid = undefined, setCustomAppViewDid] = useStorage( 7 - device, 8 - ['customAppViewDid'], 9 - ) 10 - 11 - return [customAppViewDid, setCustomAppViewDid] as const 12 - } 13 - 14 - export function readCustomAppViewDidUri() { 15 - const maybeDid = device.get(['customAppViewDid']) 16 - if (!maybeDid || !isDid(maybeDid)) { 17 - return undefined 18 - } 19 - 20 - return `${maybeDid}#bsky_appview` as `did:${string}:${string}#bsky_appview` 21 - }
+3 -4
src/state/queries/app-passwords.ts
··· 3 3 4 4 import {STALE} from '#/state/queries' 5 5 import {useAgent} from '../session' 6 - import {pdsAgent} from '../session/agent' 7 6 8 7 const RQKEY_ROOT = 'app-passwords' 9 8 export const RQKEY = () => [RQKEY_ROOT] ··· 14 13 staleTime: STALE.MINUTES.FIVE, 15 14 queryKey: RQKEY(), 16 15 queryFn: async () => { 17 - const res = await pdsAgent(agent).com.atproto.server.listAppPasswords({}) 16 + const res = await agent.com.atproto.server.listAppPasswords({}) 18 17 return res.data.passwords 19 18 }, 20 19 }) ··· 30 29 >({ 31 30 mutationFn: async ({name, privileged}) => { 32 31 return ( 33 - await pdsAgent(agent).com.atproto.server.createAppPassword({ 32 + await agent.com.atproto.server.createAppPassword({ 34 33 name, 35 34 privileged, 36 35 }) ··· 49 48 const agent = useAgent() 50 49 return useMutation<void, Error, {name: string}>({ 51 50 mutationFn: async ({name}) => { 52 - await pdsAgent(agent).com.atproto.server.revokeAppPassword({ 51 + await agent.com.atproto.server.revokeAppPassword({ 53 52 name, 54 53 }) 55 54 },
+2 -3
src/state/queries/list.ts
··· 17 17 import {type ImageMeta} from '#/state/gallery' 18 18 import {STALE} from '#/state/queries' 19 19 import {useAgent, useSession} from '#/state/session' 20 - import {pdsAgent} from '#/state/session/agent' 21 20 import {invalidate as invalidateMyLists} from './my-lists' 22 21 import {RQKEY as PROFILE_LISTS_RQKEY} from './profile-lists' 23 22 ··· 153 152 record.avatar = undefined 154 153 } 155 154 const res = ( 156 - await pdsAgent(agent).com.atproto.repo.putRecord({ 155 + await agent.com.atproto.repo.putRecord({ 157 156 repo: currentAccount.did, 158 157 collection: 'app.bsky.graph.list', 159 158 rkey, ··· 232 231 233 232 // apply in chunks 234 233 for (const writesChunk of chunk(writes, 10)) { 235 - await pdsAgent(agent).com.atproto.repo.applyWrites({ 234 + await agent.com.atproto.repo.applyWrites({ 236 235 repo: currentAccount.did, 237 236 writes: writesChunk, 238 237 })
+2 -3
src/state/queries/messages/actor-declaration.ts
··· 3 3 4 4 import {logger} from '#/logger' 5 5 import {useAgent, useSession} from '#/state/session' 6 - import {pdsAgent} from '#/state/session/agent' 7 6 import {RQKEY as PROFILE_RKEY} from '../profile' 8 7 9 8 export function useUpdateActorDeclaration({ ··· 20 19 return useMutation({ 21 20 mutationFn: async (allowIncoming: 'all' | 'none' | 'following') => { 22 21 if (!currentAccount) throw new Error('Not signed in') 23 - const result = await pdsAgent(agent).com.atproto.repo.putRecord({ 22 + const result = await agent.com.atproto.repo.putRecord({ 24 23 repo: currentAccount.did, 25 24 collection: 'chat.bsky.actor.declaration', 26 25 rkey: 'self', ··· 70 69 return useMutation({ 71 70 mutationFn: async () => { 72 71 if (!currentAccount) throw new Error('Not signed in') 73 - const result = await pdsAgent(agent).com.atproto.repo.deleteRecord({ 72 + const result = await agent.api.com.atproto.repo.deleteRecord({ 74 73 repo: currentAccount.did, 75 74 collection: 'chat.bsky.actor.declaration', 76 75 rkey: 'self',
+1 -2
src/state/queries/postgate/index.ts
··· 21 21 POSTGATE_COLLECTION, 22 22 } from '#/state/queries/postgate/util' 23 23 import {useAgent} from '#/state/session' 24 - import {pdsAgent} from '#/state/session/agent' 25 24 import * as bsky from '#/types/bsky' 26 25 27 26 export async function getPostgateRecord({ ··· 97 96 const postUrip = new AtUri(postUri) 98 97 99 98 await networkRetry(2, () => 100 - pdsAgent(agent).com.atproto.repo.putRecord({ 99 + agent.api.com.atproto.repo.putRecord({ 101 100 repo: agent.session!.did, 102 101 collection: POSTGATE_COLLECTION, 103 102 rkey: postUrip.rkey,
+3 -4
src/state/queries/preferences/index.ts
··· 20 20 type ThreadViewPreferences, 21 21 type UsePreferencesQueryResponse, 22 22 } from '#/state/queries/preferences/types' 23 - import {useBlankPrefAuthedAgent as useAgent} from '#/state/session' 24 - import {pdsAgent} from '#/state/session/agent' 23 + import {useAgent} from '#/state/session' 25 24 import {saveLabelers} from '#/state/session/agent-config' 26 25 import {useAgeAssurance} from '#/ageAssurance' 27 26 import {makeAgeRestrictedModerationPrefs} from '#/ageAssurance/util' ··· 46 45 if (!agent.did) { 47 46 return DEFAULT_LOGGED_OUT_PREFERENCES 48 47 } else { 49 - const res = await pdsAgent(agent).getPreferences() 48 + const res = await agent.getPreferences() 50 49 51 50 // save to local storage to ensure there are labels on initial requests 52 51 saveLabelers( ··· 101 100 102 101 return useMutation({ 103 102 mutationFn: async () => { 104 - await pdsAgent(agent).app.bsky.actor.putPreferences({preferences: []}) 103 + await agent.app.bsky.actor.putPreferences({preferences: []}) 105 104 // triggers a refetch 106 105 await queryClient.invalidateQueries({ 107 106 queryKey: preferencesQueryKey,
+15 -57
src/state/queries/resolve-identity.ts
··· 1 - import {type Did, isDid} from '@atproto/api' 2 - import {useQuery} from '@tanstack/react-query' 3 - 4 - import {STALE} from '.' 5 1 import {LRU} from './direct-fetch-record' 6 - const RQKEY_ROOT = 'resolve-identity' 7 - export const RQKEY = (did: string) => [RQKEY_ROOT, did] 8 2 9 - // this isn't trusted... 10 - export type DidDocument = { 11 - '@context'?: string[] 12 - id?: string 13 - alsoKnownAs?: string[] 14 - verificationMethod?: VerificationMethod[] 15 - service?: Service[] 16 - } 17 - 18 - export type VerificationMethod = { 19 - id?: string 20 - type?: string 21 - controller?: string 22 - publicKeyMultibase?: string 23 - } 24 - 25 - export type Service = { 26 - id?: string 27 - type?: string 28 - serviceEndpoint?: string 29 - } 3 + const serviceCache = new LRU<`did:${string}`, string>() 30 4 31 - const serviceCache = new LRU<Did, DidDocument>() 32 - 33 - export async function resolveDidDocument(did: Did) { 5 + export async function resolvePdsServiceUrl(did: `did:${string}`) { 34 6 return await serviceCache.getOrTryInsertWith(did, async () => { 35 7 const docUrl = did.startsWith('did:plc:') 36 8 ? `https://plc.directory/${did}` 37 9 : `https://${did.substring(8)}/.well-known/did.json` 38 10 39 - // TODO: we should probably validate this... 40 - return await (await fetch(docUrl)).json() 41 - }) 42 - } 43 - 44 - export function findService(doc: DidDocument, id: string, type?: string) { 45 - // probably not defensive enough, but we don't have atproto/did as a dep... 46 - if (!Array.isArray(doc?.service)) return 47 - return doc.service.find( 48 - s => s?.serviceEndpoint && s?.id === id && (!type || s?.type === type), 49 - ) 50 - } 51 - 52 - export async function resolvePdsServiceUrl(did: Did) { 53 - const doc = await resolveDidDocument(did) 54 - return findService(doc, '#atproto_pds', 'AtprotoPersonalDataServer') 55 - ?.serviceEndpoint 56 - } 11 + // TODO: validate! 12 + const doc: { 13 + service: { 14 + serviceEndpoint: string 15 + type: string 16 + }[] 17 + } = await (await fetch(docUrl)).json() 18 + const service = doc.service.find( 19 + s => s.type === 'AtprotoPersonalDataServer', 20 + )?.serviceEndpoint 57 21 58 - export function useDidDocument({did}: {did: string}) { 59 - return useQuery<DidDocument | undefined>({ 60 - staleTime: STALE.HOURS.ONE, 61 - queryKey: RQKEY(did || ''), 62 - async queryFn() { 63 - if (!isDid(did)) return undefined 64 - return await resolveDidDocument(did) 65 - }, 66 - enabled: isDid(did) && !(did.includes('#') || did.includes('?')), 22 + if (service === undefined) 23 + throw new Error(`could not find a service for ${did}`) 24 + return service 67 25 }) 68 26 }
+3 -4
src/state/queries/starter-packs.ts
··· 27 27 import {STALE} from '#/state/queries/index' 28 28 import {invalidateListMembersQuery} from '#/state/queries/list-members' 29 29 import {useAgent} from '#/state/session' 30 - import {pdsAgent} from '#/state/session/agent' 31 30 import * as bsky from '#/types/bsky' 32 31 33 32 const RQKEY_ROOT = 'starter-pack' ··· 204 203 if (removedItems.length !== 0) { 205 204 const chunks = chunk(removedItems, 50) 206 205 for (const chunk of chunks) { 207 - await pdsAgent(agent).com.atproto.repo.applyWrites({ 206 + await agent.com.atproto.repo.applyWrites({ 208 207 repo: agent.session!.did, 209 208 writes: chunk.map(i => ({ 210 209 $type: 'com.atproto.repo.applyWrites#delete', ··· 221 220 if (addedProfiles.length > 0) { 222 221 const chunks = chunk(addedProfiles, 50) 223 222 for (const chunk of chunks) { 224 - await pdsAgent(agent).com.atproto.repo.applyWrites({ 223 + await agent.com.atproto.repo.applyWrites({ 225 224 repo: agent.session!.did, 226 225 writes: chunk.map(p => ({ 227 226 $type: 'com.atproto.repo.applyWrites#create', ··· 238 237 } 239 238 240 239 const rkey = parseStarterPackUri(currentStarterPack.uri)!.rkey 241 - await pdsAgent(agent).com.atproto.repo.putRecord({ 240 + await agent.com.atproto.repo.putRecord({ 242 241 repo: agent.session!.did, 243 242 collection: 'app.bsky.graph.starterpack', 244 243 rkey,
+1 -2
src/state/queries/threadgate/index.ts
··· 18 18 } from '#/state/queries/threadgate/util' 19 19 import {useUpdatePostThreadThreadgateQueryCache} from '#/state/queries/usePostThread' 20 20 import {useAgent} from '#/state/session' 21 - import {pdsAgent} from '#/state/session/agent' 22 21 import {useThreadgateHiddenReplyUrisAPI} from '#/state/threadgate-hidden-replies' 23 22 import * as bsky from '#/types/bsky' 24 23 ··· 163 162 }) 164 163 165 164 await networkRetry(2, () => 166 - pdsAgent(agent).com.atproto.repo.putRecord({ 165 + agent.api.com.atproto.repo.putRecord({ 167 166 repo: agent.session!.did, 168 167 collection: 'app.bsky.feed.threadgate', 169 168 rkey: postUrip.rkey,
+10 -27
src/state/session/agent.ts
··· 15 15 16 16 import {networkRetry} from '#/lib/async/retry' 17 17 import { 18 - APPVIEW_DID_PROXY, 19 18 BLUESKY_PROXY_HEADER, 20 19 BSKY_SERVICE, 21 20 DISCOVER_SAVED_FEED, ··· 34 33 setCreatedAtForDid, 35 34 } from '#/ageAssurance/data' 36 35 import {emitNetworkConfirmed, emitNetworkLost} from '../events' 37 - import {readCustomAppViewDidUri} from '../preferences/custom-appview-did' 38 36 import {addSessionErrorLog} from './logging' 39 37 import { 40 38 configureModerationForAccount, ··· 49 47 configureModerationForGuest() // Side effect but only relevant for tests 50 48 51 49 const agent = new BskyAppAgent({service: PUBLIC_BSKY_SERVICE}) 52 - const proxyDid = 53 - readCustomAppViewDidUri() || BLUESKY_PROXY_HEADER.get() || APPVIEW_DID_PROXY 54 - agent.configureProxy(proxyDid) 50 + agent.configureProxy(BLUESKY_PROXY_HEADER.get()) 55 51 return agent 56 52 } 57 53 ··· 92 88 // after session is attached 93 89 const aa = prefetchAgeAssuranceData({agent}) 94 90 95 - const proxyDid = 96 - readCustomAppViewDidUri() || BLUESKY_PROXY_HEADER.get() || APPVIEW_DID_PROXY 97 - agent.configureProxy(proxyDid) 91 + agent.configureProxy(BLUESKY_PROXY_HEADER.get()) 98 92 99 93 return agent.prepare({ 100 94 resolvers: [gates, moderation, aa], ··· 133 127 const moderation = configureModerationForAccount(agent, account) 134 128 const aa = prefetchAgeAssuranceData({agent}) 135 129 136 - const proxyDid = 137 - readCustomAppViewDidUri() || BLUESKY_PROXY_HEADER.get() || APPVIEW_DID_PROXY 138 - agent.configureProxy(proxyDid) 130 + agent.configureProxy(BLUESKY_PROXY_HEADER.get()) 139 131 140 132 return agent.prepare({ 141 133 resolvers: [gates, moderation, aa], ··· 242 234 }), 243 235 getAge(birthDate) < 18 && 244 236 networkRetry(3, () => { 245 - return pdsAgent(agent).com.atproto.repo.putRecord({ 237 + return agent.com.atproto.repo.putRecord({ 246 238 repo: account.did, 247 239 collection: 'chat.bsky.actor.declaration', 248 240 rkey: 'self', ··· 307 299 logger.error(e, {message: `session: failed snoozeEmailConfirmationPrompt`}) 308 300 } 309 301 310 - const proxyDid = 311 - readCustomAppViewDidUri() || BLUESKY_PROXY_HEADER.get() || APPVIEW_DID_PROXY 312 - agent.configureProxy(proxyDid) 302 + agent.configureProxy(BLUESKY_PROXY_HEADER.get()) 313 303 314 304 return agent.prepare({ 315 305 resolvers: [gates, moderation, aa], ··· 342 332 accessJwt: agent.session.accessJwt, 343 333 signupQueued: isSignupQueued(agent.session.accessJwt), 344 334 active: agent.session.active, 345 - status: agent.session.status as SessionAccount['status'], 335 + status: agent.session.status, 346 336 pdsUrl: agent.pdsUrl?.toString(), 347 337 isSelfHosted: !agent.serviceUrl.toString().startsWith(BSKY_SERVICE), 348 338 } ··· 415 405 } 416 406 }, 417 407 }) 418 - const proxyDid = readCustomAppViewDidUri() || APPVIEW_DID_PROXY 419 - if (proxyDid) { 420 - this.configureProxy(proxyDid) 421 - } 422 408 } 423 409 424 410 async prepare({ ··· 451 437 this.sessionManager.session = undefined 452 438 this.persistSessionHandler = undefined 453 439 } 454 - 455 - cloneWithoutProxy(): BskyAgent { 456 - const cloned = new BskyAgent({service: this.serviceUrl.toString()}) 457 - cloned.sessionManager.session = this.sessionManager.session 458 - return cloned 459 - } 460 440 } 461 441 462 442 /** ··· 465 445 * other PDS-specific operations like preferences. 466 446 */ 467 447 export function pdsAgent<T extends BaseAgent>(agent: T): T { 468 - if ('cloneWithoutProxy' in agent && typeof agent.cloneWithoutProxy === 'function') { 448 + if ( 449 + 'cloneWithoutProxy' in agent && 450 + typeof agent.cloneWithoutProxy === 'function' 451 + ) { 469 452 return agent.cloneWithoutProxy() as T 470 453 } 471 454 const clone = agent.clone() as T
+2 -14
src/state/session/index.tsx
··· 1 - import React, {useMemo} from 'react' 1 + import React from 'react' 2 2 import {type AtpSessionEvent, type BskyAgent} from '@atproto/api' 3 3 4 4 import * as persisted from '#/state/persisted' ··· 12 12 createAgentAndCreateAccount, 13 13 createAgentAndLogin, 14 14 createAgentAndResume, 15 - pdsAgent, 16 15 sessionAccountToSession, 17 16 } from './agent' 18 17 import {type Action, getInitialState, reducer, type State} from './reducer' ··· 249 248 >(async () => { 250 249 const agent = state.currentAgentState.agent as BskyAppAgent 251 250 const signal = cancelPendingTask() 252 - const {data} = await pdsAgent(agent).com.atproto.server.getSession() 251 + const {data} = await agent.com.atproto.server.getSession() 253 252 if (signal.aborted) return 254 253 store.dispatch({ 255 254 type: 'partial-refresh-session', ··· 411 410 } 412 411 return agent 413 412 } 414 - 415 - export function useBlankPrefAuthedAgent(): BskyAgent { 416 - const agent = React.useContext(AgentContext) 417 - if (!agent) { 418 - throw Error('useAgent() must be below <SessionProvider>.') 419 - } 420 - 421 - return useMemo(() => { 422 - return (agent as BskyAppAgent).cloneWithoutProxy() 423 - }, [agent]) 424 - }
-1
src/storage/schema.ts
··· 52 52 deerGateCache: string 53 53 activitySubscriptionsNudged?: boolean 54 54 threadgateNudged?: boolean 55 - customAppViewDid: string | undefined 56 55 57 56 /** 58 57 * Policy update overlays. New IDs are required for each new announcement.
+2 -3
src/view/com/modals/DeleteAccount.tsx
··· 18 18 import {useTheme} from '#/lib/ThemeContext' 19 19 import {useModalControls} from '#/state/modals' 20 20 import {useAgent, useSession, useSessionApi} from '#/state/session' 21 - import {pdsAgent} from '#/state/session/agent' 22 21 import {atoms as a, useTheme as useNewTheme, utils} from '#/alf' 23 22 import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' 24 23 import {Text as NewText} from '#/components/Typography' ··· 50 49 setError('') 51 50 setIsProcessing(true) 52 51 try { 53 - await pdsAgent(agent).com.atproto.server.requestAccountDelete() 52 + await agent.com.atproto.server.requestAccountDelete() 54 53 setIsEmailSent(true) 55 54 } catch (e: any) { 56 55 setError(cleanError(e)) ··· 77 76 if (!success) { 78 77 throw new Error('Failed to inform chat service of account deletion') 79 78 } 80 - await pdsAgent(agent).com.atproto.server.deleteAccount({ 79 + await agent.com.atproto.server.deleteAccount({ 81 80 did: currentAccount.did, 82 81 password, 83 82 token,