migrate the signup and onboarding profile writes to sdk actions

The post-signup and onboarding writes (setPersonalDetails, upsertProfile,
overwriteSavedFeeds, setInterestsPref) move onto sdk actions over the pds
client, and the starter-pack and contact-import reads move to the lex
clients. Every upsertProfile call now writes a lex blob directly, so the
toLegacyBlobRef bridge has no remaining callers and is deleted.
This commit is contained in:
Samuel Newman
2026-08-04 01:38:37 +03:00
parent 926abd0566
commit a40c199523
6 changed files with 92 additions and 117 deletions
+40 -40
View File
@@ -2,24 +2,21 @@ import {useContext} from 'react'
import {Alert, View} from 'react-native'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import * as Contacts from 'expo-contacts'
import type AtpAgent from '@atproto/api'
import {
type AppBskyActorProfile,
AppBskyContactImportContacts,
type Un$Typed,
} from '@atproto/api'
import {type Un$Typed} from '@atproto/lex'
import {type Client} from '@atproto/lex'
import {toDatetimeString} from '@atproto/syntax'
import {upsertProfile} from '@bsky.app/sdk'
import {msg, t} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro'
import {useMutation, useQueryClient} from '@tanstack/react-query'
import {uploadBlob} from '#/lib/api'
import {toLegacyBlobRef} from '#/lib/api/legacy-blob'
import {cleanError, isNetworkError} from '#/lib/strings/errors'
import {matchXrpcError} from '#/lib/xrpc-error'
import {logger} from '#/logger'
import {findContactsStatusQueryKey} from '#/state/queries/find-contacts'
import {useAgent, usePdsClient} from '#/state/session'
import {useAppviewClient, usePdsClient} from '#/state/session'
import {
Context as OnboardingContext,
type OnboardingAction,
@@ -32,6 +29,7 @@ import {Loader} from '#/components/Loader'
import * as Toast from '#/components/Toast'
import {Text} from '#/components/Typography'
import {useAnalytics} from '#/analytics'
import {app} from '#/lexicons'
import {
contactsWithPhoneNumbersOnly,
filterMatchedNumbers,
@@ -56,8 +54,8 @@ export function GetContacts({
}) {
const {_} = useLingui()
const ax = useAnalytics()
const agent = useAgent()
const pdsClient = usePdsClient()
const appviewClient = useAppviewClient()
const insets = useSafeAreaInsets()
const gutters = useGutters([0, 'wide'])
const queryClient = useQueryClient()
@@ -75,7 +73,7 @@ export function GetContacts({
*/
if (context === 'Onboarding' && maybeOnboardingContext) {
try {
await createProfileRecord(agent, pdsClient, maybeOnboardingContext)
await createProfileRecord(pdsClient, maybeOnboardingContext)
} catch (error) {
logger.debug('Error creating profile record:', {safeMessage: error})
}
@@ -88,13 +86,13 @@ export function GetContacts({
)
if (phoneNumbers.length > 0) {
const res = await agent.app.bsky.contact.importContacts({
const res = await appviewClient.call(app.bsky.contact.importContacts, {
token: state.token,
contacts: phoneNumbers.slice(0, MAX_UPLOAD_COUNT),
})
return {
matches: res.data.matchesAndContactIndexes,
matches: res.matchesAndContactIndexes,
indexToContactId,
}
} else {
@@ -151,29 +149,30 @@ export function GetContacts({
),
{type: 'error'},
)
} else if (
err instanceof AppBskyContactImportContacts.TooManyContactsError
) {
Toast.show(
_(
msg`Too many contacts - you've exceeded the number of contacts you can import to find your friends`,
),
{type: 'error'},
)
} else if (
err instanceof AppBskyContactImportContacts.InvalidTokenError
) {
Toast.show(
_(
msg`Could not upload contacts. You need to re-verify your phone number to proceed`,
),
{type: 'error'},
)
} else {
logger.error('Error uploading contacts', {safeMessage: err})
Toast.show(_(msg`Could not upload contacts. ${cleanError(err)}`), {
type: 'error',
})
return
}
switch (matchXrpcError(err, app.bsky.contact.importContacts)) {
case 'TooManyContacts':
Toast.show(
_(
msg`Too many contacts - you've exceeded the number of contacts you can import to find your friends`,
),
{type: 'error'},
)
break
case 'InvalidToken':
Toast.show(
_(
msg`Could not upload contacts. You need to re-verify your phone number to proceed`,
),
{type: 'error'},
)
break
default:
logger.error('Error uploading contacts', {safeMessage: err})
Toast.show(_(msg`Could not upload contacts. ${cleanError(err)}`), {
type: 'error',
})
}
},
})
@@ -328,7 +327,6 @@ function showPermissionDeniedAlert() {
* Copied from `#/screens/Onboarding/StepFinished/index.tsx`
*/
async function createProfileRecord(
agent: AtpAgent,
pdsClient: Client,
onboardingContext: {
state: OnboardingState
@@ -342,19 +340,21 @@ async function createProfileRecord(
? uploadBlob(pdsClient, imageUri, imageMime)
: undefined
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 (blobPromise) {
const res = await blobPromise
if (res.blob) {
next.avatar = toLegacyBlobRef(res.blob)
next.avatar = res.blob
}
}
next.displayName = ''
next.createdAt = new Date().toISOString()
if (!next.createdAt) {
next.createdAt = toDatetimeString(new Date())
}
return next
})
}
@@ -6,7 +6,6 @@ import {
type AtIdentifierString,
AtUri,
type AtUriString,
type DidString,
toDatetimeString,
} from '@atproto/syntax'
import {msg} from '@lingui/core/macro'
@@ -86,8 +85,7 @@ export function CreateListFromStarterPackDialog({
items.map(item => {
const listitemRecord: $Typed<app.bsky.graph.listitem.Main> = {
$type: 'app.bsky.graph.listitem',
// the list view is still legacy-typed, so its strings are unbranded
subject: item.subject.did as DidString,
subject: item.subject.did,
list: listUri as AtUriString,
createdAt: toDatetimeString(new Date()),
}