[SDK] Migrate agent sugar to @bsky.app/sdk actions (#11382)

This commit is contained in:
Samuel Newman
2026-08-13 22:26:21 +03:00
committed by GitHub
parent a4f2811f39
commit dc31e7fd12
24 changed files with 520 additions and 389 deletions
+7 -4
View File
@@ -1,9 +1,10 @@
import {useMemo} from 'react'
import {setPersonalDetails} from '@bsky.app/sdk'
import {useMutation, useQueryClient} from '@tanstack/react-query'
import {restrictChatSettings} from '#/state/queries/messages/restrictChatSettings'
import {preferencesQueryKey} from '#/state/queries/preferences'
import {useAgent, usePdsClient, useSession} from '#/state/session'
import {usePdsClient, useSession} from '#/state/session'
import {usePatchAgeAssuranceOtherRequiredData} from '#/ageAssurance'
import {isUnderAge} from '#/ageAssurance/util'
import {IS_DEV} from '#/env'
@@ -54,14 +55,14 @@ export function useIsBirthdateUpdateAllowed() {
export function useBirthdateMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const {currentAccount} = useSession()
const pdsClient = usePdsClient()
const patchOtherRequiredData = usePatchAgeAssuranceOtherRequiredData()
return useMutation<void, unknown, {birthDate: Date}>({
mutationFn: async ({birthDate}: {birthDate: Date}) => {
const bday = birthDate.toISOString()
await agent.setPersonalDetails({birthDate: bday})
await pdsClient.call(setPersonalDetails, {birthDate})
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
@@ -80,7 +81,9 @@ export function useBirthdateMutation() {
* birthdate, which may change the user's age assurance access level.
*/
void patchOtherRequiredData({birthdate: bday})
snoozeBirthdateUpdateAllowedForDid(agent.sessionManager.did!)
if (currentAccount) {
snoozeBirthdateUpdateAllowedForDid(currentAccount.did)
}
},
})
}
+15 -6
View File
@@ -1,4 +1,6 @@
import {type AppBskyLabelerDefs} from '@atproto/api'
import {type DidString} from '@atproto/syntax'
import {addLabeler, removeLabeler} from '@bsky.app/sdk'
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
import {z} from 'zod'
@@ -9,7 +11,7 @@ import {
usePreferencesQuery,
} from '#/state/queries/preferences'
import {createQueryKey} from '#/state/queries/util'
import {useAgent} from '#/state/session'
import {useAgent, usePdsClient} from '#/state/session'
const labelerInfoQueryKeyRoot = 'labeler-info'
export const labelerInfoQueryKey = (did: string) => [
@@ -78,11 +80,13 @@ export function useLabelersDetailedInfoQuery({dids}: {dids: string[]}) {
export function useRemoveLabelersMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation({
async mutationFn({dids}: {dids: string[]}) {
await Promise.all(dids.map(did => agent.removeLabeler(did)))
await Promise.all(
dids.map(did => client.call(removeLabeler, did as DidString)),
)
},
async onSuccess() {
await queryClient.invalidateQueries({
@@ -95,6 +99,7 @@ export function useRemoveLabelersMutation() {
export function useLabelerSubscriptionMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const pdsClient = usePdsClient()
const preferences = usePreferencesQuery()
return useMutation({
@@ -136,7 +141,11 @@ export function useLabelerSubscriptionMutation() {
}
}
if (invalidLabelers.length) {
await Promise.all(invalidLabelers.map(did => agent.removeLabeler(did)))
await Promise.all(
invalidLabelers.map(did =>
pdsClient.call(removeLabeler, did as DidString),
),
)
}
if (subscribe) {
@@ -144,9 +153,9 @@ export function useLabelerSubscriptionMutation() {
if (labelerCount >= MAX_LABELERS) {
throw new Error('MAX_LABELERS')
}
await agent.addLabeler(did)
await pdsClient.call(addLabeler, did as DidString)
} else {
await agent.removeLabeler(did)
await pdsClient.call(removeLabeler, did as DidString)
}
},
async onSuccess() {
+10 -5
View File
@@ -1,22 +1,27 @@
import {type AtUriString} from '@atproto/syntax'
import {deleteLike, like} from '@bsky.app/sdk'
import {useMutation} from '@tanstack/react-query'
import {useAgent} from '#/state/session'
import {usePdsClient} from '#/state/session'
export function useLikeMutation() {
const agent = useAgent()
const pdsClient = usePdsClient()
return useMutation({
mutationFn: async ({uri, cid}: {uri: string; cid: string}) => {
const res = await agent.like(uri, cid)
const res = await pdsClient.call(like, {
uri: uri as AtUriString,
cid,
})
return {uri: res.uri}
},
})
}
export function useUnlikeMutation() {
const agent = useAgent()
const pdsClient = usePdsClient()
return useMutation({
mutationFn: async ({uri}: {uri: string}) => {
await agent.deleteLike(uri)
await pdsClient.call(deleteLike, uri as AtUriString)
},
})
}
+1 -1
View File
@@ -61,7 +61,7 @@ export function useAllListMembersQuery(uri?: string) {
export async function getAllListMembers(client: Client, uri: string) {
let hasMore = true
let cursor: string | undefined
const listItems: AppBskyGraphDefs.ListItemView[] = []
const listItems: app.bsky.graph.defs.ListItemView[] = []
// We want to cap this at 6 pages, just for anything weird happening with the api
let i = 0
while (hasMore && i < 6) {
+12 -14
View File
@@ -6,6 +6,12 @@ import {
type AtUriString,
toDatetimeString,
} from '@atproto/syntax'
import {
blockActorList,
muteActorList,
unblockActorList,
unmuteActorList,
} from '@bsky.app/sdk'
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
import chunk from 'lodash.chunk'
@@ -13,12 +19,7 @@ import {uploadBlob} from '#/lib/api'
import {until} from '#/lib/async/until'
import {type ImageMeta} from '#/state/gallery'
import {STALE} from '#/state/queries'
import {
useAgent,
useAppviewClient,
usePdsClient,
useSession,
} from '#/state/session'
import {useAppviewClient, usePdsClient, useSession} from '#/state/session'
import {app, com} from '#/lexicons'
import {FEED_INFO_RQKEY_ROOT} from './feed'
import {invalidate as invalidateMyLists} from './my-lists'
@@ -255,15 +256,13 @@ export function useListDeleteMutation() {
export function useListMuteMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const appviewClient = useAppviewClient()
return useMutation<void, Error, {uri: string; mute: boolean}>({
mutationFn: async ({uri, mute}) => {
// `muteModList`/`unmuteModList` are preference writes, migrated in wave B
if (mute) {
await agent.muteModList(uri)
await appviewClient.call(muteActorList, {list: uri as AtUriString})
} else {
await agent.unmuteModList(uri)
await appviewClient.call(unmuteActorList, {list: uri as AtUriString})
}
await whenAppViewReady(appviewClient, uri, v => {
@@ -280,15 +279,14 @@ export function useListMuteMutation() {
export function useListBlockMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const appviewClient = useAppviewClient()
const pdsClient = usePdsClient()
return useMutation<void, Error, {uri: string; block: boolean}>({
mutationFn: async ({uri, block}) => {
// `blockModList`/`unblockModList` write a block record, migrated in wave B
if (block) {
await agent.blockModList(uri)
await pdsClient.call(blockActorList, {list: uri as AtUriString})
} else {
await agent.unblockModList(uri)
await pdsClient.call(unblockActorList, {list: uri as AtUriString})
}
await whenAppViewReady(appviewClient, uri, v => {
@@ -1,15 +1,12 @@
import type AtpAgent from '@atproto/api'
import {
type AppBskyActorDefs,
type ChatBskyActorDeclaration,
} from '@atproto/api'
import {type AppBskyActorDefs} from '@atproto/api'
import {type Client} from '@atproto/lex'
import {type DidString} from '@atproto/syntax'
import {useMutation, useQueryClient} from '@tanstack/react-query'
import {logger} from '#/logger'
import {usePdsClient, useSession} from '#/state/session'
import {resolveAllowGroupInvites} from '#/components/dms/util'
import {com} from '#/lexicons'
import {chat, com} from '#/lexicons'
import {RQKEY as PROFILE_RKEY} from '../profile'
export function useUpdateActorDeclaration({
@@ -119,25 +116,16 @@ export function useDeleteActorDeclaration() {
})
}
/*
* Still takes the legacy agent: its only caller is `getOtherRequiredData` in
* `#/ageAssurance/data`, which is blocked on `getPreferences` and so cannot
* hand over a lex client yet.
*/
export async function fetchActorDeclarationRecord({
agent,
client,
did,
}: {
agent: AtpAgent
client: Client
did?: string
}) {
if (!did) return
const res = await agent.com.atproto.repo
.getRecord({
repo: did,
collection: 'chat.bsky.actor.declaration',
rkey: 'self',
})
const res = await client
.get(chat.bsky.actor.declaration, {repo: did as DidString, rkey: 'self'})
.catch(_e => undefined)
return res?.data.value as ChatBskyActorDeclaration.Main
return res?.value
}
+16 -7
View File
@@ -1,3 +1,4 @@
import {removeNuxs, upsertNux} from '@bsky.app/sdk'
import {useMutation, useQueryClient} from '@tanstack/react-query'
import {type AppNux, type Nux} from '#/state/queries/nuxs/definitions'
@@ -6,7 +7,8 @@ import {
preferencesQueryKey,
usePreferencesQuery,
} from '#/state/queries/preferences'
import {useAgent} from '#/state/session'
import {usePdsClient} from '#/state/session'
import {type app} from '#/lexicons'
export {Nux} from '#/state/queries/nuxs/definitions'
@@ -42,11 +44,11 @@ export function useNuxs():
// if (__DEV__) {
// const queryClient = useQueryClient()
// const agent = useAgent()
// const pdsClient = usePdsClient()
// // @ts-ignore
// window.clearNux = async (ids: string[]) => {
// await agent.bskyAppRemoveNuxs(ids)
// await pdsClient.call(removeNuxs, ids)
// // triggers a refetch
// await queryClient.invalidateQueries({
// queryKey: preferencesQueryKey,
@@ -97,12 +99,19 @@ export function useNux<T extends Nux>(
export function useSaveNux() {
const queryClient = useQueryClient()
const agent = useAgent()
const pdsClient = usePdsClient()
return useMutation({
retry: 3,
mutationFn: async (nux: AppNux) => {
await agent.bskyAppUpsertNux(serializeAppNux(nux))
/*
* `serializeAppNux` still returns the legacy `Nux`, whose strings are
* unbranded; it is validated against the same schema the action expects.
*/
await pdsClient.call(
upsertNux,
serializeAppNux(nux) as app.bsky.actor.defs.Nux,
)
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
@@ -113,12 +122,12 @@ export function useSaveNux() {
export function useResetNuxs() {
const queryClient = useQueryClient()
const agent = useAgent()
const pdsClient = usePdsClient()
return useMutation({
retry: 3,
mutationFn: async (ids: string[]) => {
await agent.bskyAppRemoveNuxs(ids)
await pdsClient.call(removeNuxs, ids)
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
+6 -2
View File
@@ -6,7 +6,7 @@ import {useMutation, useQueryClient} from '@tanstack/react-query'
import {logger} from '#/logger'
import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
import * as Toast from '#/components/Toast'
import {app} from '#/lexicons'
import {app, type com} from '#/lexicons'
import {updatePostShadow} from '../cache/post-shadow'
import {useAppviewClient, useSession} from '../session'
import {useProfileUpdateMutation} from './profile'
@@ -47,7 +47,11 @@ export function usePinnedPostMutation() {
profile,
updates: existing => {
existing.pinnedPost = pinCurrentPost
? {uri: postUri, cid: postCid}
? // the caller's uri/cid are unbranded strings
({
uri: postUri,
cid: postCid,
} as com.atproto.repo.strongRef.Main)
: undefined
return existing
},
@@ -1,8 +1,9 @@
import {type AppBskyActorDefs} from '@atproto/api'
import {setPostInteractionSettings} from '@bsky.app/sdk'
import {useMutation, useQueryClient} from '@tanstack/react-query'
import {preferencesQueryKey} from '#/state/queries/preferences'
import {useAgent} from '#/state/session'
import {usePdsClient} from '#/state/session'
import {type app} from '#/lexicons'
export function usePostInteractionSettingsMutation({
onError,
@@ -12,10 +13,10 @@ export function usePostInteractionSettingsMutation({
onSettled?: () => void
} = {}) {
const qc = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation({
async mutationFn(props: AppBskyActorDefs.PostInteractionSettingsPref) {
await agent.setPostInteractionSettings(props)
async mutationFn(props: app.bsky.actor.defs.PostInteractionSettingsPref) {
await client.call(setPostInteractionSettings, props)
},
async onSuccess() {
await qc.invalidateQueries({
+39 -17
View File
@@ -1,5 +1,7 @@
import {useCallback} from 'react'
import {type AppBskyActorDefs, type AppBskyFeedDefs, AtUri} from '@atproto/api'
import {type AtUriString} from '@atproto/syntax'
import {deleteLike, deletePost, deleteRepost, like, repost} from '@bsky.app/sdk'
import {
type QueryClient,
useMutation,
@@ -10,10 +12,16 @@ import {
import {useToggleMutationQueue} from '#/lib/hooks/useToggleMutationQueue'
import {updatePostShadow} from '#/state/cache/post-shadow'
import {type Shadow} from '#/state/cache/types'
import {useAgent, useSession} from '#/state/session'
import {
useAgent,
useAppviewClient,
usePdsClient,
useSession,
} from '#/state/session'
import * as userActionHistory from '#/state/userActionHistory'
import {useAnalytics} from '#/analytics'
import {type Metrics, toClout} from '#/analytics/metrics'
import {app} from '#/lexicons'
import {useIsThreadMuted, useSetThreadMute} from '../cache/thread-mutes'
import {findProfileQueryData} from './profile'
@@ -184,7 +192,7 @@ function usePostLikeMutation(
const {currentAccount} = useSession()
const queryClient = useQueryClient()
const postAuthor = post.author
const agent = useAgent()
const pdsClient = usePdsClient()
const ax = useAnalytics()
return useMutation<
{uri: string}, // responds with the uri of the like
@@ -215,7 +223,11 @@ function usePostLikeMutation(
: undefined,
feedDescriptor: feedDescriptor,
})
return agent.like(uri, cid, via)
return pdsClient.call(like, {
uri: uri as AtUriString,
cid: cid,
via: via ? {uri: via.uri as AtUriString, cid: via.cid} : undefined,
})
},
})
}
@@ -225,7 +237,7 @@ function usePostUnlikeMutation(
logContext: Metrics['post:unlike']['logContext'],
post: Shadow<AppBskyFeedDefs.PostView>,
) {
const agent = useAgent()
const pdsClient = usePdsClient()
const ax = useAnalytics()
return useMutation<void, Error, {postUri: string; likeUri: string}>({
mutationFn: ({postUri, likeUri}) => {
@@ -235,7 +247,7 @@ function usePostUnlikeMutation(
logContext,
feedDescriptor,
})
return agent.deleteLike(likeUri)
return pdsClient.call(deleteLike, likeUri as AtUriString)
},
})
}
@@ -309,7 +321,7 @@ function usePostRepostMutation(
logContext: Metrics['post:repost']['logContext'],
post: Shadow<AppBskyFeedDefs.PostView>,
) {
const agent = useAgent()
const pdsClient = usePdsClient()
const ax = useAnalytics()
return useMutation<
{uri: string}, // responds with the uri of the repost
@@ -323,7 +335,11 @@ function usePostRepostMutation(
logContext,
feedDescriptor,
})
return agent.repost(uri, cid, via)
return pdsClient.call(repost, {
uri: uri as AtUriString,
cid: cid,
via: via ? {uri: via.uri as AtUriString, cid: via.cid} : undefined,
})
},
})
}
@@ -333,7 +349,7 @@ function usePostUnrepostMutation(
logContext: Metrics['post:unrepost']['logContext'],
post: Shadow<AppBskyFeedDefs.PostView>,
) {
const agent = useAgent()
const pdsClient = usePdsClient()
const ax = useAnalytics()
return useMutation<void, Error, {postUri: string; repostUri: string}>({
mutationFn: ({postUri, repostUri}) => {
@@ -343,17 +359,17 @@ function usePostUnrepostMutation(
logContext,
feedDescriptor,
})
return agent.deleteRepost(repostUri)
return pdsClient.call(deleteRepost, repostUri as AtUriString)
},
})
}
export function usePostDeleteMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const pdsClient = usePdsClient()
return useMutation<void, Error, {uri: string}>({
mutationFn: async ({uri}) => {
await agent.deletePost(uri)
await pdsClient.call(deletePost, uri as AtUriString)
},
onSuccess(_, variables) {
updatePostShadow(queryClient, variables.uri, {isDeleted: true})
@@ -407,23 +423,29 @@ export function useThreadMuteMutationQueue(
}
function useThreadMuteMutation() {
const agent = useAgent()
const appviewClient = useAppviewClient()
return useMutation<
{},
Error,
{uri: string} // the root post's uri
>({
mutationFn: ({uri}) => {
return agent.api.app.bsky.graph.muteThread({root: uri})
mutationFn: async ({uri}) => {
await appviewClient.call(app.bsky.graph.muteThread, {
root: uri as AtUriString,
})
return {}
},
})
}
function useThreadUnmuteMutation() {
const agent = useAgent()
const appviewClient = useAppviewClient()
return useMutation<{}, Error, {uri: string}>({
mutationFn: ({uri}) => {
return agent.api.app.bsky.graph.unmuteThread({root: uri})
mutationFn: async ({uri}) => {
await appviewClient.call(app.bsky.graph.unmuteThread, {
root: uri as AtUriString,
})
return {}
},
})
}
+114 -54
View File
@@ -1,9 +1,28 @@
import {useCallback} from 'react'
import {type AppBskyActorDefs} from '@atproto/api'
import {type DidString} from '@atproto/syntax'
import {
type AppBskyActorDefs,
addSavedFeeds,
type BskyFeedViewPreference,
type LabelPreference,
} from '@atproto/api'
dismissNudges,
getPreferences,
overwriteSavedFeeds,
queueNudges,
removeMutedWord,
removeMutedWords,
removeSavedFeeds,
setActiveProgressGuide,
setAdultContentEnabled,
setContentLabelPref,
setFeedViewPrefs,
setIsBetaUser,
setThreadViewPrefs,
setVerificationPrefs,
updateMutedWord,
updateSavedFeeds,
upsertMutedWords,
} from '@bsky.app/sdk'
import {type LabelPreference} from '@bsky.app/sdk/moderation'
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
import {PROD_DEFAULT_FEED} from '#/lib/constants'
@@ -20,11 +39,12 @@ import {
type UsePreferencesQueryResponse,
} from '#/state/queries/preferences/types'
import {createQueryKey} from '#/state/queries/util'
import {useAgent} from '#/state/session'
import {useAgent, usePdsClient} from '#/state/session'
import {saveLabelers} from '#/state/session/moderation'
import {useAgeAssurance} from '#/ageAssurance'
import {makeAgeRestrictedModerationPrefs} from '#/ageAssurance/util'
import {useAnalytics} from '#/analytics'
import {app} from '#/lexicons'
export * from '#/state/queries/preferences/const'
export * from '#/state/queries/preferences/moderation'
@@ -37,6 +57,7 @@ export const preferencesQueryKey = createQueryKey(
)
export function usePreferencesQuery() {
const client = usePdsClient()
const agent = useAgent()
const aa = useAgeAssurance()
@@ -47,18 +68,34 @@ export function usePreferencesQuery() {
queryKey: preferencesQueryKey,
gcTime: GCTIME.INFINITY,
queryFn: async () => {
if (!agent.did) {
if (!client.did) {
return DEFAULT_LOGGED_OUT_PREFERENCES
} else {
const res = await agent.getPreferences()
const res = await client.call(getPreferences)
const labelerDids = res.moderationPrefs.labelers.map(l => l.did)
// save to local storage to ensure there are labels on initial requests
saveLabelers(
agent.did,
res.moderationPrefs.labelers.map(l => l.did),
)
saveLabelers(client.did, labelerDids)
const preferences: UsePreferencesQueryResponse = {
/*
* `BskyAgent.getPreferences` used to call `configureLabelers` itself,
* so subscribing to a labeler took effect on the very next appview
* read. The sdk action has no such side effect, and appview reads still
* inherit `atproto-accept-labelers` from the agent's fetch handler, so
* apply the subscriptions there rather than on the wrapping client -
* setting them on both would emit the header twice.
*/
agent.configureLabelers(labelerDids)
/*
* The sdk's `BskyPreferences` is field-for-field identical to the
* legacy one that `UsePreferencesQueryResponse` is still derived from;
* only its strings are branded (`AtUriString`, `DidString`). Cast at
* this one seam so every downstream consumer of the response - notably
* the `moderationPrefs` readers - keeps its current types.
*/
const preferences = {
...res,
savedFeeds: res.savedFeeds.filter(f => f.type !== 'unknown'),
/**
@@ -74,7 +111,7 @@ export function usePreferencesQuery() {
...(res.threadViewPrefs ?? {}),
},
userAge: res.birthDate ? getAge(res.birthDate) : undefined,
}
} as UsePreferencesQueryResponse
return preferences
}
},
@@ -113,11 +150,11 @@ export function usePreferencesQuery() {
export function useClearPreferencesMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation({
mutationFn: async () => {
await agent.app.bsky.actor.putPreferences({preferences: []})
await client.call(app.bsky.actor.putPreferences, {preferences: []})
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
@@ -128,7 +165,7 @@ export function useClearPreferencesMutation() {
export function usePreferencesSetContentLabelMutation() {
const ax = useAnalytics()
const agent = useAgent()
const client = usePdsClient()
const queryClient = useQueryClient()
return useMutation<
@@ -137,7 +174,11 @@ export function usePreferencesSetContentLabelMutation() {
{label: string; visibility: LabelPreference; labelerDid: string | undefined}
>({
mutationFn: async ({label, visibility, labelerDid}) => {
await agent.setContentLabelPref(label, visibility, labelerDid)
await client.call(setContentLabelPref, {
key: label,
value: visibility,
labelerDid: labelerDid as DidString | undefined,
})
ax.metric('moderation:changeLabelPreference', {preference: visibility})
// triggers a refetch
await queryClient.invalidateQueries({
@@ -149,7 +190,7 @@ export function usePreferencesSetContentLabelMutation() {
export function useSetContentLabelMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation({
mutationFn: async ({
@@ -161,7 +202,11 @@ export function useSetContentLabelMutation() {
visibility: LabelPreference
labelerDid?: string
}) => {
await agent.setContentLabelPref(label, visibility, labelerDid)
await client.call(setContentLabelPref, {
key: label,
value: visibility,
labelerDid: labelerDid as DidString | undefined,
})
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
@@ -172,11 +217,11 @@ export function useSetContentLabelMutation() {
export function usePreferencesSetAdultContentMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation<void, unknown, {enabled: boolean}>({
mutationFn: async ({enabled}) => {
await agent.setAdultContentEnabled(enabled)
await client.call(setAdultContentEnabled, enabled)
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
@@ -187,7 +232,7 @@ export function usePreferencesSetAdultContentMutation() {
export function useSetFeedViewPreferencesMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation<void, unknown, Partial<BskyFeedViewPreference>>({
mutationFn: async prefs => {
@@ -195,7 +240,7 @@ export function useSetFeedViewPreferencesMutation() {
* special handling here, merged into `feedViewPrefs` above, since
* following was previously called `home`
*/
await agent.setFeedViewPrefs('home', prefs)
await client.call(setFeedViewPrefs, {feed: 'home', ...prefs})
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
@@ -212,11 +257,11 @@ export function useSetThreadViewPreferencesMutation({
onError?: (error: unknown) => void
}) {
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation<void, unknown, Partial<ThreadViewPreferences>>({
mutationFn: async prefs => {
await agent.setThreadViewPrefs(prefs)
await client.call(setThreadViewPrefs, prefs)
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
@@ -229,11 +274,11 @@ export function useSetThreadViewPreferencesMutation({
export function useOverwriteSavedFeedsMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation<void, unknown, AppBskyActorDefs.SavedFeed[]>({
mutationFn: async savedFeeds => {
await agent.overwriteSavedFeeds(savedFeeds)
await client.call(overwriteSavedFeeds, savedFeeds)
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
@@ -244,7 +289,7 @@ export function useOverwriteSavedFeedsMutation() {
export function useAddSavedFeedsMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation<
void,
@@ -252,7 +297,7 @@ export function useAddSavedFeedsMutation() {
Pick<AppBskyActorDefs.SavedFeed, 'type' | 'value' | 'pinned'>[]
>({
mutationFn: async savedFeeds => {
await agent.addSavedFeeds(savedFeeds)
await client.call(addSavedFeeds, savedFeeds)
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
@@ -263,11 +308,11 @@ export function useAddSavedFeedsMutation() {
export function useRemoveFeedMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation<void, unknown, Pick<AppBskyActorDefs.SavedFeed, 'id'>>({
mutationFn: async savedFeed => {
await agent.removeSavedFeeds([savedFeed.id])
await client.call(removeSavedFeeds, [savedFeed.id])
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
@@ -278,7 +323,7 @@ export function useRemoveFeedMutation() {
export function useReplaceForYouWithDiscoverFeedMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation({
mutationFn: async ({
@@ -289,10 +334,10 @@ export function useReplaceForYouWithDiscoverFeedMutation() {
discoverFeedConfig: AppBskyActorDefs.SavedFeed | undefined
}) => {
if (forYouFeedConfig) {
await agent.removeSavedFeeds([forYouFeedConfig.id])
await client.call(removeSavedFeeds, [forYouFeedConfig.id])
}
if (!discoverFeedConfig) {
await agent.addSavedFeeds([
await client.call(addSavedFeeds, [
{
type: 'feed',
value: PROD_DEFAULT_FEED('whats-hot'),
@@ -300,7 +345,7 @@ export function useReplaceForYouWithDiscoverFeedMutation() {
},
])
} else {
await agent.updateSavedFeeds([
await client.call(updateSavedFeeds, [
{
...discoverFeedConfig,
pinned: true,
@@ -317,11 +362,11 @@ export function useReplaceForYouWithDiscoverFeedMutation() {
export function useUpdateSavedFeedsMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation<void, unknown, AppBskyActorDefs.SavedFeed[]>({
mutationFn: async feeds => {
await agent.updateSavedFeeds(feeds)
await client.call(updateSavedFeeds, feeds)
// triggers a refetch
await queryClient.invalidateQueries({
@@ -333,11 +378,14 @@ export function useUpdateSavedFeedsMutation() {
export function useUpsertMutedWordsMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation({
mutationFn: async (mutedWords: AppBskyActorDefs.MutedWord[]) => {
await agent.upsertMutedWords(mutedWords)
await client.call(
upsertMutedWords,
mutedWords as app.bsky.actor.defs.MutedWord[],
)
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
@@ -348,11 +396,14 @@ export function useUpsertMutedWordsMutation() {
export function useUpdateMutedWordMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation({
mutationFn: async (mutedWord: AppBskyActorDefs.MutedWord) => {
await agent.updateMutedWord(mutedWord)
await client.call(
updateMutedWord,
mutedWord as app.bsky.actor.defs.MutedWord,
)
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
@@ -363,11 +414,14 @@ export function useUpdateMutedWordMutation() {
export function useRemoveMutedWordMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation({
mutationFn: async (mutedWord: AppBskyActorDefs.MutedWord) => {
await agent.removeMutedWord(mutedWord)
await client.call(
removeMutedWord,
mutedWord as app.bsky.actor.defs.MutedWord,
)
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
@@ -378,11 +432,14 @@ export function useRemoveMutedWordMutation() {
export function useRemoveMutedWordsMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation({
mutationFn: async (mutedWords: AppBskyActorDefs.MutedWord[]) => {
await agent.removeMutedWords(mutedWords)
await client.call(
removeMutedWords,
mutedWords as app.bsky.actor.defs.MutedWord[],
)
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
@@ -393,11 +450,11 @@ export function useRemoveMutedWordsMutation() {
export function useQueueNudgesMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation({
mutationFn: async (nudges: string | string[]) => {
await agent.bskyAppQueueNudges(nudges)
await client.call(queueNudges, Array.isArray(nudges) ? nudges : [nudges])
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
@@ -408,11 +465,14 @@ export function useQueueNudgesMutation() {
export function useDismissNudgesMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation({
mutationFn: async (nudges: string | string[]) => {
await agent.bskyAppDismissNudges(nudges)
await client.call(
dismissNudges,
Array.isArray(nudges) ? nudges : [nudges],
)
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
@@ -423,13 +483,13 @@ export function useDismissNudgesMutation() {
export function useSetActiveProgressGuideMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation({
mutationFn: async (
guide: AppBskyActorDefs.BskyAppProgressGuide | undefined,
) => {
await agent.bskyAppSetActiveProgressGuide(guide)
await client.call(setActiveProgressGuide, guide)
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
@@ -440,11 +500,11 @@ export function useSetActiveProgressGuideMutation() {
export function useSetIsBetaUserMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation({
mutationFn: async (isBetaUser: boolean) => {
await agent.setIsBetaUser(isBetaUser)
await client.call(setIsBetaUser, isBetaUser)
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
@@ -456,11 +516,11 @@ export function useSetIsBetaUserMutation() {
export function useSetVerificationPrefsMutation() {
const ax = useAnalytics()
const queryClient = useQueryClient()
const agent = useAgent()
const client = usePdsClient()
return useMutation<void, unknown, AppBskyActorDefs.VerificationPrefs>({
mutationFn: async prefs => {
await agent.setVerificationPrefs(prefs)
await client.call(setVerificationPrefs, prefs)
if (prefs.hideBadges) {
ax.metric('verification:settings:hideBadges', {})
} else {
+75 -60
View File
@@ -3,17 +3,24 @@ import {
type AppBskyActorDefs,
type AppBskyActorGetProfile,
type AppBskyActorGetProfiles,
type AppBskyActorProfile,
type AppBskyGraphGetFollows,
type AtpAgent,
AtUri,
type Un$Typed,
} from '@atproto/api'
import {type Client} from '@atproto/lex'
import {
type AtIdentifierString,
type AtUriString,
type DidString,
toDatetimeString,
} from '@atproto/syntax'
import {
deleteFollow,
follow,
muteActor,
unmuteActor,
upsertProfile,
} from '@bsky.app/sdk'
import {
type InfiniteData,
keepPreviousData,
@@ -24,7 +31,6 @@ import {
} from '@tanstack/react-query'
import {uploadBlob} from '#/lib/api'
import {toLegacyBlobRef} from '#/lib/api/legacy-blob'
import {until} from '#/lib/async/until'
import {useToggleMutationQueue} from '#/lib/hooks/useToggleMutationQueue'
import {updateProfileShadow} from '#/state/cache/profile-shadow'
@@ -38,7 +44,7 @@ import {
useUnstableProfileViewCache,
} from '#/state/queries/unstable-profile-cache'
import {useUpdateProfileVerificationCache} from '#/state/queries/verification/useUpdateProfileVerificationCache'
import {useAgent, usePdsClient, useSession} from '#/state/session'
import {useAppviewClient, usePdsClient, useSession} from '#/state/session'
import * as userActionHistory from '#/state/userActionHistory'
import {useAnalytics} from '#/analytics'
import {type Metrics, toClout} from '#/analytics/metrics'
@@ -74,7 +80,7 @@ export function useProfileQuery({
did: string | undefined
staleTime?: number
}) {
const agent = useAgent()
const client = useAppviewClient()
const {getUnstableProfile} = useUnstableProfileViewCache()
return useQuery<AppBskyActorDefs.ProfileViewDetailed>({
// WARNING
@@ -85,8 +91,9 @@ export function useProfileQuery({
refetchOnWindowFocus: true,
queryKey: RQKEY(did ?? ''),
queryFn: async () => {
const res = await agent.getProfile({actor: did ?? ''})
return res.data
return await client.call(app.bsky.actor.getProfile, {
actor: (did ?? '') as AtIdentifierString,
})
},
placeholderData: () => {
if (!did) return
@@ -103,21 +110,22 @@ export function useProfilesQuery({
handles: string[]
maintainData?: boolean
}) {
const agent = useAgent()
const client = useAppviewClient()
return useQuery({
enabled: handles.length > 0,
staleTime: STALE.MINUTES.FIVE,
queryKey: profilesQueryKey(handles),
queryFn: async () => {
const res = await agent.getProfiles({actors: handles})
return res.data
return await client.call(app.bsky.actor.getProfiles, {
actors: handles as AtIdentifierString[],
})
},
placeholderData: maintainData ? keepPreviousData : undefined,
})
}
export function usePrefetchProfileQuery() {
const agent = useAgent()
const client = useAppviewClient()
const queryClient = useQueryClient()
const prefetchProfileQuery = useCallback(
async (did: string) => {
@@ -125,12 +133,13 @@ export function usePrefetchProfileQuery() {
staleTime: STALE.SECONDS.THIRTY,
queryKey: RQKEY(did),
queryFn: async () => {
const res = await agent.getProfile({actor: did || ''})
return res.data
return await client.call(app.bsky.actor.getProfile, {
actor: (did || '') as AtIdentifierString,
})
},
})
},
[queryClient, agent],
[queryClient, client],
)
return prefetchProfileQuery
}
@@ -138,18 +147,18 @@ export function usePrefetchProfileQuery() {
interface ProfileUpdateParams {
profile: AppBskyActorDefs.ProfileViewDetailed
updates:
| Un$Typed<AppBskyActorProfile.Record>
| Un$Typed<app.bsky.actor.profile.Main>
| ((
existing: Un$Typed<AppBskyActorProfile.Record>,
) => Un$Typed<AppBskyActorProfile.Record>)
existing: Un$Typed<app.bsky.actor.profile.Main>,
) => Un$Typed<app.bsky.actor.profile.Main>)
newUserAvatar?: ImageMeta | undefined | null
newUserBanner?: ImageMeta | undefined | null
checkCommitted?: (res: AppBskyActorGetProfile.Response) => boolean
}
export function useProfileUpdateMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
const pdsClient = usePdsClient()
const appviewClient = useAppviewClient()
const updateProfileVerificationCache = useUpdateProfileVerificationCache()
return useMutation<void, Error, ProfileUpdateParams>({
mutationFn: async ({
@@ -175,8 +184,8 @@ export function useProfileUpdateMutation() {
newUserBanner.mime,
)
}
await agent.upsertProfile(async existing => {
let next: Un$Typed<AppBskyActorProfile.Record> = existing || {}
await pdsClient.call(upsertProfile, async existing => {
let next: Un$Typed<app.bsky.actor.profile.Main> = existing || {}
if (typeof updates === 'function') {
next = updates(next)
} else {
@@ -188,20 +197,20 @@ export function useProfileUpdateMutation() {
}
if (newUserAvatarPromise) {
const res = await newUserAvatarPromise
next.avatar = toLegacyBlobRef(res.blob)
next.avatar = res.blob
} else if (newUserAvatar === null) {
next.avatar = undefined
}
if (newUserBannerPromise) {
const res = await newUserBannerPromise
next.banner = toLegacyBlobRef(res.blob)
next.banner = res.blob
} else if (newUserBanner === null) {
next.banner = undefined
}
return next
})
await whenAppViewReady(
agent,
appviewClient,
profile.did,
checkCommitted ||
(res => {
@@ -252,7 +261,7 @@ export function useProfileFollowMutationQueue(
position?: number,
contextProfileDid?: string,
) {
const agent = useAgent()
const client = useAppviewClient()
const queryClient = useQueryClient()
const {currentAccount} = useSession()
const did = profile.did
@@ -333,12 +342,12 @@ export function useProfileFollowMutationQueue(
}
if (finalFollowingUri) {
void agent.app.bsky.graph
.getSuggestedFollowsByActor({
actor: did,
void client
.call(app.bsky.graph.getSuggestedFollowsByActor, {
actor: did as AtIdentifierString,
})
.then(res => {
const dids = res.data.suggestions
const dids = res.suggestions
.filter(a => !a.viewer?.following)
.map(a => a.did)
.slice(0, 8)
@@ -375,7 +384,7 @@ function useProfileFollowMutation(
) {
const ax = useAnalytics()
const {currentAccount} = useSession()
const agent = useAgent()
const pdsClient = usePdsClient()
const queryClient = useQueryClient()
const {captureAction} = useProgressGuideControls()
@@ -400,7 +409,7 @@ function useProfileFollowMutation(
position,
contextProfileDid,
})
return await agent.follow(did)
return await pdsClient.call(follow, {did: did as DidString})
},
})
}
@@ -409,11 +418,11 @@ function useProfileUnfollowMutation(
logContext: Metrics['profile:unfollow']['logContext'],
) {
const ax = useAnalytics()
const agent = useAgent()
const pdsClient = usePdsClient()
return useMutation<void, Error, {did: string; followUri: string}>({
mutationFn: async ({followUri}) => {
ax.metric('profile:unfollow', {logContext})
return await agent.deleteFollow(followUri)
return await pdsClient.call(deleteFollow, followUri as AtUriString)
},
})
}
@@ -423,7 +432,7 @@ export function useProfileMuteMutationQueue(
) {
const ax = useAnalytics()
const queryClient = useQueryClient()
const did = profile.did
const did = profile.did as DidString
const initialMuted = profile.viewer?.muted
const muteMutation = useProfileMuteMutation()
const unmuteMutation = useProfileUnmuteMutation()
@@ -432,15 +441,11 @@ export function useProfileMuteMutationQueue(
initialState: initialMuted,
runMutation: async (_prevMuted, shouldMute) => {
if (shouldMute) {
await muteMutation.mutateAsync({
did,
})
await muteMutation.mutateAsync({did})
ax.metric('profile:mute', {})
return true
} else {
await unmuteMutation.mutateAsync({
did,
})
await unmuteMutation.mutateAsync({did})
ax.metric('profile:unmute', {})
return false
}
@@ -485,7 +490,7 @@ export function useProfileMuteRepostsMutationQueue(
) {
const ax = useAnalytics()
const queryClient = useQueryClient()
const did = profile.did
const did = profile.did as DidString
const initialMutedOnlyReposts = !!profile.viewer?.mutedOnlyReposts
const muteRepostsMutation = useProfileMuteRepostsMutation()
const unmuteMutation = useProfileUnmuteMutation()
@@ -494,15 +499,11 @@ export function useProfileMuteRepostsMutationQueue(
initialState: initialMutedOnlyReposts,
runMutation: async (_prevMutedOnlyReposts, shouldMute) => {
if (shouldMute) {
await muteRepostsMutation.mutateAsync({
did,
})
await muteRepostsMutation.mutateAsync({did})
ax.metric('profile:muteReposts', {})
return true
} else {
await unmuteMutation.mutateAsync({
did,
})
await unmuteMutation.mutateAsync({did})
ax.metric('profile:unmuteReposts', {})
return false
}
@@ -536,10 +537,10 @@ export function useProfileMuteRepostsMutationQueue(
function useProfileMuteMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
return useMutation<void, Error, {did: string}>({
mutationFn: async ({did}) => {
await agent.mute(did)
const appviewClient = useAppviewClient()
return useMutation({
mutationFn: async ({did}: {did: DidString}) => {
await appviewClient.call(muteActor, {actor: did})
},
onSuccess() {
void queryClient.invalidateQueries({queryKey: RQKEY_MY_MUTED()})
@@ -549,10 +550,14 @@ function useProfileMuteMutation() {
function useProfileMuteRepostsMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
return useMutation<void, Error, {did: string}>({
mutationFn: async ({did}) => {
await agent.mute(did, {onlyReposts: true})
const appviewClient = useAppviewClient()
return useMutation({
mutationFn: async ({did}: {did: DidString}) => {
await appviewClient.call(muteActor, {
actor: did,
// @ts-expect-error missing from this SDK version, remove this
onlyReposts: true,
})
},
onSuccess() {
void queryClient.invalidateQueries({queryKey: RQKEY_MY_MUTED()})
@@ -562,10 +567,10 @@ function useProfileMuteRepostsMutation() {
function useProfileUnmuteMutation() {
const queryClient = useQueryClient()
const agent = useAgent()
return useMutation<void, Error, {did: string}>({
mutationFn: async ({did}) => {
await agent.unmute(did)
const appviewClient = useAppviewClient()
return useMutation({
mutationFn: async ({did}: {did: DidString}) => {
await appviewClient.call(unmuteActor, {actor: did})
},
onSuccess() {
void queryClient.invalidateQueries({queryKey: RQKEY_MY_MUTED()})
@@ -679,7 +684,7 @@ function useProfileUnblockMutation() {
}
async function whenAppViewReady(
agent: AtpAgent,
client: Client,
actor: string,
fn: (res: AppBskyActorGetProfile.Response) => boolean,
) {
@@ -687,7 +692,17 @@ async function whenAppViewReady(
5, // 5 tries
1e3, // 1s delay between tries
fn,
() => agent.app.bsky.actor.getProfile({actor}),
/*
* `checkCommitted` callbacks are still written against the legacy
* `Response` envelope, so wrap the lex output until those consumers move.
*/
async () => ({
success: true,
headers: {},
data: await client.call(app.bsky.actor.getProfile, {
actor: actor as AtIdentifierString,
}),
}),
)
}
+28 -22
View File
@@ -1,7 +1,12 @@
import {type AppBskyActorProfile, type Un$Typed} from '@atproto/api'
import {TID} from '@atproto/common-web'
import {type Client} from '@atproto/lex'
import {PasswordSession} from '@atproto/lex-password-session'
import {toDatetimeString} from '@atproto/syntax'
import {
overwriteSavedFeeds,
setPersonalDetails,
upsertProfile,
} from '@bsky.app/sdk'
import {networkRetry} from '#/lib/async/retry'
import {
@@ -21,8 +26,8 @@ import {
} from '#/ageAssurance/data'
import {unsafeGetAndComputeAgeAssurance} from '#/ageAssurance/state'
import {features} from '#/analytics'
import {type BskyAppAgent} from './bridge-agent'
import {agentToPdsClient} from './clients'
import {type app} from '#/lexicons'
import {agentToAppviewClient, agentToPdsClient} from './clients'
import {configureModerationForAccount} from './moderation'
import {
buildBundle,
@@ -88,7 +93,7 @@ export async function createSessionBundleAndCreateAccount(
const gates = features.refresh({strategy: 'prefer-fresh-gates'})
configureModerationForAccount(bundle.agent, earlyAccount)
const createdAt = new Date().toISOString()
const createdAt = toDatetimeString(new Date())
const birthdate = birthDate.toISOString()
/*
@@ -100,22 +105,23 @@ export async function createSessionBundleAndCreateAccount(
setCreatedAtForDid({did: earlyAccount.did, createdAt})
setBirthdateForDid({did: earlyAccount.did, birthdate})
snoozeBirthdateUpdateAllowedForDid(earlyAccount.did)
// Post-signup writes all target the account's own repo and actor store.
const pdsClient = agentToPdsClient(bundle.agent)
// Start the prefetch after seeding its synchronous birthdate inputs.
const aa = prefetchAgeAssuranceServerData({agent: bundle.agent})
const aa = prefetchAgeAssuranceServerData({
appviewClient: agentToAppviewClient(bundle.agent),
accountClient: pdsClient,
})
const isProd = Boolean(IS_PROD_SERVICE(service))
const postSignupTasks: Promise<unknown>[] = [
savePersonalDetails(bundle.agent, birthdate),
initializeProfile(bundle.agent, {handle, createdAt, isProd}),
savePersonalDetails(pdsClient, birthDate),
initializeProfile(pdsClient, {handle, createdAt, isProd}),
]
if (isProd) {
postSignupTasks.push(
initializeSavedFeeds(bundle.agent),
restrictChatAfterAgeAssurance(
aa,
agentToPdsClient(bundle.agent),
earlyAccount.did,
),
initializeSavedFeeds(pdsClient),
restrictChatAfterAgeAssurance(aa, pdsClient, earlyAccount.did),
)
}
// Post-signup writes are not required to enter onboarding.
@@ -170,41 +176,41 @@ function snapshotNewAccount(
}
}
function savePersonalDetails(agent: BskyAppAgent, birthDate: string) {
function savePersonalDetails(client: Client, birthDate: Date) {
return retryPostSignupTask('set birthDate', 3, () =>
agent.setPersonalDetails({birthDate}),
client.call(setPersonalDetails, {birthDate}),
)
}
function initializeProfile(
agent: BskyAppAgent,
client: Client,
{
handle,
createdAt,
isProd,
}: {
handle: string
createdAt: string
createdAt: ReturnType<typeof toDatetimeString>
isProd: boolean
},
) {
return retryPostSignupTask('set initial profile', 3, () =>
agent.upsertProfile(prev => {
const next: Un$Typed<AppBskyActorProfile.Record> = prev || {}
client.call(upsertProfile, prev => {
const next: Partial<app.bsky.actor.profile.Main> = prev || {}
if (isProd) {
next.displayName = handle
next.createdAt = createdAt
} else {
next.createdAt = prev?.createdAt || new Date().toISOString()
next.createdAt = prev?.createdAt || toDatetimeString(new Date())
}
return next
}),
)
}
function initializeSavedFeeds(agent: BskyAppAgent) {
function initializeSavedFeeds(client: Client) {
return retryPostSignupTask('set initial feeds', 1, () =>
agent.overwriteSavedFeeds([
client.call(overwriteSavedFeeds, [
{...DISCOVER_SAVED_FEED, id: TID.nextStr()},
{...TIMELINE_SAVED_FEED, id: TID.nextStr()},
]),
+9 -2
View File
@@ -13,6 +13,7 @@ import {
createPublicAgent,
PasswordSessionManager,
} from './bridge-agent'
import {agentToAppviewClient, agentToPdsClient} from './clients'
import {addSessionErrorLog} from './logging'
import {configureModerationForAccount} from './moderation'
import {networkAwareFetch} from './network'
@@ -290,7 +291,10 @@ export async function createSessionBundleAndResume(
) ?? storedAccount
configureModerationForAccount(bundle.agent, earlyAccount)
const aa = prefetchAgeAssuranceServerData({agent: bundle.agent})
const aa = prefetchAgeAssuranceServerData({
appviewClient: agentToAppviewClient(bundle.agent),
accountClient: agentToPdsClient(bundle.agent),
})
/*
* The proxy header is applied after the PDS-targeting setup above, so those
@@ -355,7 +359,10 @@ export async function createSessionBundleAndLogin(
const gates = features.refresh({strategy: 'prefer-fresh-gates'})
configureModerationForAccount(bundle.agent, earlyAccount)
const aa = prefetchAgeAssuranceServerData({agent: bundle.agent})
const aa = prefetchAgeAssuranceServerData({
appviewClient: agentToAppviewClient(bundle.agent),
accountClient: agentToPdsClient(bundle.agent),
})
bundle.agent.configureProxy(BLUESKY_PROXY_HEADER.get())