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:
@@ -2,24 +2,21 @@ import {useContext} from 'react'
|
|||||||
import {Alert, View} from 'react-native'
|
import {Alert, View} from 'react-native'
|
||||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||||
import * as Contacts from 'expo-contacts'
|
import * as Contacts from 'expo-contacts'
|
||||||
import type AtpAgent from '@atproto/api'
|
import {type Un$Typed} from '@atproto/lex'
|
||||||
import {
|
|
||||||
type AppBskyActorProfile,
|
|
||||||
AppBskyContactImportContacts,
|
|
||||||
type Un$Typed,
|
|
||||||
} from '@atproto/api'
|
|
||||||
import {type Client} 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 {msg, t} from '@lingui/core/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {Trans} from '@lingui/react/macro'
|
import {Trans} from '@lingui/react/macro'
|
||||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {uploadBlob} from '#/lib/api'
|
import {uploadBlob} from '#/lib/api'
|
||||||
import {toLegacyBlobRef} from '#/lib/api/legacy-blob'
|
|
||||||
import {cleanError, isNetworkError} from '#/lib/strings/errors'
|
import {cleanError, isNetworkError} from '#/lib/strings/errors'
|
||||||
|
import {matchXrpcError} from '#/lib/xrpc-error'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {findContactsStatusQueryKey} from '#/state/queries/find-contacts'
|
import {findContactsStatusQueryKey} from '#/state/queries/find-contacts'
|
||||||
import {useAgent, usePdsClient} from '#/state/session'
|
import {useAppviewClient, usePdsClient} from '#/state/session'
|
||||||
import {
|
import {
|
||||||
Context as OnboardingContext,
|
Context as OnboardingContext,
|
||||||
type OnboardingAction,
|
type OnboardingAction,
|
||||||
@@ -32,6 +29,7 @@ import {Loader} from '#/components/Loader'
|
|||||||
import * as Toast from '#/components/Toast'
|
import * as Toast from '#/components/Toast'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {useAnalytics} from '#/analytics'
|
import {useAnalytics} from '#/analytics'
|
||||||
|
import {app} from '#/lexicons'
|
||||||
import {
|
import {
|
||||||
contactsWithPhoneNumbersOnly,
|
contactsWithPhoneNumbersOnly,
|
||||||
filterMatchedNumbers,
|
filterMatchedNumbers,
|
||||||
@@ -56,8 +54,8 @@ export function GetContacts({
|
|||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
const agent = useAgent()
|
|
||||||
const pdsClient = usePdsClient()
|
const pdsClient = usePdsClient()
|
||||||
|
const appviewClient = useAppviewClient()
|
||||||
const insets = useSafeAreaInsets()
|
const insets = useSafeAreaInsets()
|
||||||
const gutters = useGutters([0, 'wide'])
|
const gutters = useGutters([0, 'wide'])
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
@@ -75,7 +73,7 @@ export function GetContacts({
|
|||||||
*/
|
*/
|
||||||
if (context === 'Onboarding' && maybeOnboardingContext) {
|
if (context === 'Onboarding' && maybeOnboardingContext) {
|
||||||
try {
|
try {
|
||||||
await createProfileRecord(agent, pdsClient, maybeOnboardingContext)
|
await createProfileRecord(pdsClient, maybeOnboardingContext)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.debug('Error creating profile record:', {safeMessage: error})
|
logger.debug('Error creating profile record:', {safeMessage: error})
|
||||||
}
|
}
|
||||||
@@ -88,13 +86,13 @@ export function GetContacts({
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (phoneNumbers.length > 0) {
|
if (phoneNumbers.length > 0) {
|
||||||
const res = await agent.app.bsky.contact.importContacts({
|
const res = await appviewClient.call(app.bsky.contact.importContacts, {
|
||||||
token: state.token,
|
token: state.token,
|
||||||
contacts: phoneNumbers.slice(0, MAX_UPLOAD_COUNT),
|
contacts: phoneNumbers.slice(0, MAX_UPLOAD_COUNT),
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
matches: res.data.matchesAndContactIndexes,
|
matches: res.matchesAndContactIndexes,
|
||||||
indexToContactId,
|
indexToContactId,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -151,29 +149,30 @@ export function GetContacts({
|
|||||||
),
|
),
|
||||||
{type: 'error'},
|
{type: 'error'},
|
||||||
)
|
)
|
||||||
} else if (
|
return
|
||||||
err instanceof AppBskyContactImportContacts.TooManyContactsError
|
}
|
||||||
) {
|
switch (matchXrpcError(err, app.bsky.contact.importContacts)) {
|
||||||
Toast.show(
|
case 'TooManyContacts':
|
||||||
_(
|
Toast.show(
|
||||||
msg`Too many contacts - you've exceeded the number of contacts you can import to find your friends`,
|
_(
|
||||||
),
|
msg`Too many contacts - you've exceeded the number of contacts you can import to find your friends`,
|
||||||
{type: 'error'},
|
),
|
||||||
)
|
{type: 'error'},
|
||||||
} else if (
|
)
|
||||||
err instanceof AppBskyContactImportContacts.InvalidTokenError
|
break
|
||||||
) {
|
case 'InvalidToken':
|
||||||
Toast.show(
|
Toast.show(
|
||||||
_(
|
_(
|
||||||
msg`Could not upload contacts. You need to re-verify your phone number to proceed`,
|
msg`Could not upload contacts. You need to re-verify your phone number to proceed`,
|
||||||
),
|
),
|
||||||
{type: 'error'},
|
{type: 'error'},
|
||||||
)
|
)
|
||||||
} else {
|
break
|
||||||
logger.error('Error uploading contacts', {safeMessage: err})
|
default:
|
||||||
Toast.show(_(msg`Could not upload contacts. ${cleanError(err)}`), {
|
logger.error('Error uploading contacts', {safeMessage: err})
|
||||||
type: 'error',
|
Toast.show(_(msg`Could not upload contacts. ${cleanError(err)}`), {
|
||||||
})
|
type: 'error',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -328,7 +327,6 @@ function showPermissionDeniedAlert() {
|
|||||||
* Copied from `#/screens/Onboarding/StepFinished/index.tsx`
|
* Copied from `#/screens/Onboarding/StepFinished/index.tsx`
|
||||||
*/
|
*/
|
||||||
async function createProfileRecord(
|
async function createProfileRecord(
|
||||||
agent: AtpAgent,
|
|
||||||
pdsClient: Client,
|
pdsClient: Client,
|
||||||
onboardingContext: {
|
onboardingContext: {
|
||||||
state: OnboardingState
|
state: OnboardingState
|
||||||
@@ -342,19 +340,21 @@ async function createProfileRecord(
|
|||||||
? uploadBlob(pdsClient, imageUri, imageMime)
|
? uploadBlob(pdsClient, imageUri, imageMime)
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
await agent.upsertProfile(async existing => {
|
await pdsClient.call(upsertProfile, async existing => {
|
||||||
let next: Un$Typed<AppBskyActorProfile.Record> = existing ?? {}
|
let next: Un$Typed<app.bsky.actor.profile.Main> = existing ?? {}
|
||||||
|
|
||||||
if (blobPromise) {
|
if (blobPromise) {
|
||||||
const res = await blobPromise
|
const res = await blobPromise
|
||||||
if (res.blob) {
|
if (res.blob) {
|
||||||
next.avatar = toLegacyBlobRef(res.blob)
|
next.avatar = res.blob
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
next.displayName = ''
|
next.displayName = ''
|
||||||
|
|
||||||
next.createdAt = new Date().toISOString()
|
if (!next.createdAt) {
|
||||||
|
next.createdAt = toDatetimeString(new Date())
|
||||||
|
}
|
||||||
return next
|
return next
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import {
|
|||||||
type AtIdentifierString,
|
type AtIdentifierString,
|
||||||
AtUri,
|
AtUri,
|
||||||
type AtUriString,
|
type AtUriString,
|
||||||
type DidString,
|
|
||||||
toDatetimeString,
|
toDatetimeString,
|
||||||
} from '@atproto/syntax'
|
} from '@atproto/syntax'
|
||||||
import {msg} from '@lingui/core/macro'
|
import {msg} from '@lingui/core/macro'
|
||||||
@@ -86,8 +85,7 @@ export function CreateListFromStarterPackDialog({
|
|||||||
items.map(item => {
|
items.map(item => {
|
||||||
const listitemRecord: $Typed<app.bsky.graph.listitem.Main> = {
|
const listitemRecord: $Typed<app.bsky.graph.listitem.Main> = {
|
||||||
$type: 'app.bsky.graph.listitem',
|
$type: 'app.bsky.graph.listitem',
|
||||||
// the list view is still legacy-typed, so its strings are unbranded
|
subject: item.subject.did,
|
||||||
subject: item.subject.did as DidString,
|
|
||||||
list: listUri as AtUriString,
|
list: listUri as AtUriString,
|
||||||
createdAt: toDatetimeString(new Date()),
|
createdAt: toDatetimeString(new Date()),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
import {BlobRef} from '@atproto/api'
|
|
||||||
import {type BlobRef as LexBlobRef} from '@atproto/lex'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bridge a lex blob ref (the plain-JSON `{$type: 'blob', ref, mimeType, size}`
|
|
||||||
* that {@link uploadBlob} now returns) back to the legacy `BlobRef` class
|
|
||||||
* instance.
|
|
||||||
*
|
|
||||||
* Only needed where a blob is handed to a legacy agent write: the legacy
|
|
||||||
* lexicon blob validator checks `value instanceof BlobRef`, so a plain lex
|
|
||||||
* blob fails validation, and the legacy serializer would put the wrong shape
|
|
||||||
* on the wire. Drop each call as its write moves to the lex client.
|
|
||||||
*/
|
|
||||||
export function toLegacyBlobRef(blob: LexBlobRef): BlobRef {
|
|
||||||
return BlobRef.fromJsonRef(blob as Parameters<typeof BlobRef.fromJsonRef>[0])
|
|
||||||
}
|
|
||||||
@@ -1,21 +1,19 @@
|
|||||||
import {useCallback, useState} from 'react'
|
import {useCallback, useState} from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {
|
|
||||||
type AppBskyActorDefs,
|
|
||||||
type AppBskyActorProfile,
|
|
||||||
type AppBskyGraphDefs,
|
|
||||||
AppBskyGraphStarterpack,
|
|
||||||
type Un$Typed,
|
|
||||||
} from '@atproto/api'
|
|
||||||
import {TID} from '@atproto/common-web'
|
import {TID} from '@atproto/common-web'
|
||||||
import {type AtUriString} from '@atproto/syntax'
|
import {type Un$Typed} from '@atproto/lex'
|
||||||
|
import {type AtUriString, toDatetimeString} from '@atproto/syntax'
|
||||||
|
import {
|
||||||
|
overwriteSavedFeeds,
|
||||||
|
setInterestsPref,
|
||||||
|
upsertProfile,
|
||||||
|
} from '@bsky.app/sdk'
|
||||||
import {msg} from '@lingui/core/macro'
|
import {msg} from '@lingui/core/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {Trans} from '@lingui/react/macro'
|
import {Trans} from '@lingui/react/macro'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {uploadBlob} from '#/lib/api'
|
import {uploadBlob} from '#/lib/api'
|
||||||
import {toLegacyBlobRef} from '#/lib/api/legacy-blob'
|
|
||||||
import {
|
import {
|
||||||
BSKY_APP_ACCOUNT_DID,
|
BSKY_APP_ACCOUNT_DID,
|
||||||
DISCOVER_SAVED_FEED,
|
DISCOVER_SAVED_FEED,
|
||||||
@@ -28,7 +26,7 @@ import {useSetHasCheckedForStarterPack} from '#/state/preferences/used-starter-p
|
|||||||
import {getAllListMembers} from '#/state/queries/list-members'
|
import {getAllListMembers} from '#/state/queries/list-members'
|
||||||
import {preferencesQueryKey} from '#/state/queries/preferences'
|
import {preferencesQueryKey} from '#/state/queries/preferences'
|
||||||
import {RQKEY as profileRQKey} from '#/state/queries/profile'
|
import {RQKEY as profileRQKey} from '#/state/queries/profile'
|
||||||
import {useAgent, useAppviewClient, usePdsClient} from '#/state/session'
|
import {useAppviewClient, usePdsClient} from '#/state/session'
|
||||||
import {useOnboardingDispatch} from '#/state/shell'
|
import {useOnboardingDispatch} from '#/state/shell'
|
||||||
import {
|
import {
|
||||||
useActiveStarterPack,
|
useActiveStarterPack,
|
||||||
@@ -50,6 +48,7 @@ import {ArrowRight_Stroke2_Corner0_Rounded as ArrowRight} from '#/components/ico
|
|||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {useAnalytics} from '#/analytics'
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
|
import {app} from '#/lexicons'
|
||||||
import * as bsky from '#/types/bsky'
|
import * as bsky from '#/types/bsky'
|
||||||
import {ValuePropositionPager} from './ValuePropositionPager'
|
import {ValuePropositionPager} from './ValuePropositionPager'
|
||||||
|
|
||||||
@@ -59,9 +58,8 @@ export function StepFinished() {
|
|||||||
const onboardDispatch = useOnboardingDispatch()
|
const onboardDispatch = useOnboardingDispatch()
|
||||||
const [saving, setSaving] = useState(false)
|
const [saving, setSaving] = useState(false)
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
|
||||||
const appviewClient = useAppviewClient()
|
|
||||||
const pdsClient = usePdsClient()
|
const pdsClient = usePdsClient()
|
||||||
|
const appviewClient = useAppviewClient()
|
||||||
const requestNotificationsPermission = useRequestNotificationsPermission()
|
const requestNotificationsPermission = useRequestNotificationsPermission()
|
||||||
const activeStarterPack = useActiveStarterPack()
|
const activeStarterPack = useActiveStarterPack()
|
||||||
const setActiveStarterPack = useSetActiveStarterPack()
|
const setActiveStarterPack = useSetActiveStarterPack()
|
||||||
@@ -71,15 +69,15 @@ export function StepFinished() {
|
|||||||
const finishOnboarding = useCallback(async () => {
|
const finishOnboarding = useCallback(async () => {
|
||||||
setSaving(true)
|
setSaving(true)
|
||||||
|
|
||||||
let starterPack: AppBskyGraphDefs.StarterPackView | undefined
|
let starterPack: app.bsky.graph.defs.StarterPackView | undefined
|
||||||
let listItems: AppBskyGraphDefs.ListItemView[] | undefined
|
let listItems: app.bsky.graph.defs.ListItemView[] | undefined
|
||||||
|
|
||||||
if (activeStarterPack?.uri) {
|
if (activeStarterPack?.uri) {
|
||||||
try {
|
try {
|
||||||
const spRes = await agent.app.bsky.graph.getStarterPack({
|
const spRes = await appviewClient.call(app.bsky.graph.getStarterPack, {
|
||||||
starterPack: activeStarterPack.uri,
|
starterPack: activeStarterPack.uri as AtUriString,
|
||||||
})
|
})
|
||||||
starterPack = spRes.data.starterPack
|
starterPack = spRes.starterPack
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('Failed to fetch starter pack', {safeMessage: e})
|
logger.error('Failed to fetch starter pack', {safeMessage: e})
|
||||||
// don't tell the user, just get them through onboarding.
|
// don't tell the user, just get them through onboarding.
|
||||||
@@ -109,19 +107,15 @@ export function StepFinished() {
|
|||||||
appviewClient,
|
appviewClient,
|
||||||
[BSKY_APP_ACCOUNT_DID, ...(listItems?.map(i => i.subject.did) ?? [])],
|
[BSKY_APP_ACCOUNT_DID, ...(listItems?.map(i => i.subject.did) ?? [])],
|
||||||
starterPack
|
starterPack
|
||||||
? // the starter pack view is still legacy-typed
|
? {uri: starterPack.uri, cid: starterPack.cid}
|
||||||
{
|
|
||||||
uri: starterPack.uri as AtUriString,
|
|
||||||
cid: starterPack.cid,
|
|
||||||
}
|
|
||||||
: undefined,
|
: undefined,
|
||||||
),
|
),
|
||||||
(async () => {
|
(async () => {
|
||||||
// Interests need to get saved first, then we can write the feeds to prefs
|
// Interests need to get saved first, then we can write the feeds to prefs
|
||||||
await agent.setInterestsPref({tags: selectedInterests})
|
await pdsClient.call(setInterestsPref, {tags: selectedInterests})
|
||||||
|
|
||||||
// Default feeds that every user should have pinned when landing in the app
|
// Default feeds that every user should have pinned when landing in the app
|
||||||
const feedsToSave: AppBskyActorDefs.SavedFeed[] = [
|
const feedsToSave: app.bsky.actor.defs.SavedFeed[] = [
|
||||||
{
|
{
|
||||||
...DISCOVER_SAVED_FEED,
|
...DISCOVER_SAVED_FEED,
|
||||||
id: TID.nextStr(),
|
id: TID.nextStr(),
|
||||||
@@ -140,7 +134,7 @@ export function StepFinished() {
|
|||||||
if (starterPack && starterPack.feeds?.length) {
|
if (starterPack && starterPack.feeds?.length) {
|
||||||
feedsToSave.push(
|
feedsToSave.push(
|
||||||
...starterPack.feeds.map(f => ({
|
...starterPack.feeds.map(f => ({
|
||||||
type: 'feed',
|
type: 'feed' as const,
|
||||||
value: f.uri,
|
value: f.uri,
|
||||||
pinned: true,
|
pinned: true,
|
||||||
id: TID.nextStr(),
|
id: TID.nextStr(),
|
||||||
@@ -148,7 +142,7 @@ export function StepFinished() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
await agent.overwriteSavedFeeds(feedsToSave)
|
await pdsClient.call(overwriteSavedFeeds, feedsToSave)
|
||||||
})(),
|
})(),
|
||||||
(async () => {
|
(async () => {
|
||||||
const {imageUri, imageMime} = profileStepResults
|
const {imageUri, imageMime} = profileStepResults
|
||||||
@@ -157,13 +151,13 @@ export function StepFinished() {
|
|||||||
? uploadBlob(pdsClient, imageUri, imageMime)
|
? uploadBlob(pdsClient, imageUri, imageMime)
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
await agent.upsertProfile(async existing => {
|
await pdsClient.call(upsertProfile, async existing => {
|
||||||
let next: Un$Typed<AppBskyActorProfile.Record> = existing ?? {}
|
let next: Un$Typed<app.bsky.actor.profile.Main> = existing ?? {}
|
||||||
|
|
||||||
if (blobPromise) {
|
if (blobPromise) {
|
||||||
const res = await blobPromise
|
const res = await blobPromise
|
||||||
if (res.blob) {
|
if (res.blob) {
|
||||||
next.avatar = toLegacyBlobRef(res.blob)
|
next.avatar = res.blob
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +171,7 @@ export function StepFinished() {
|
|||||||
next.displayName = ''
|
next.displayName = ''
|
||||||
|
|
||||||
if (!next.createdAt) {
|
if (!next.createdAt) {
|
||||||
next.createdAt = new Date().toISOString()
|
next.createdAt = toDatetimeString(new Date())
|
||||||
}
|
}
|
||||||
return next
|
return next
|
||||||
})
|
})
|
||||||
@@ -204,7 +198,7 @@ export function StepFinished() {
|
|||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
}),
|
}),
|
||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
queryKey: profileRQKey(agent.session?.did ?? ''),
|
queryKey: profileRQKey(pdsClient.did ?? ''),
|
||||||
}),
|
}),
|
||||||
]).catch(e => {
|
]).catch(e => {
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
@@ -221,10 +215,7 @@ export function StepFinished() {
|
|||||||
usedStarterPack: Boolean(starterPack),
|
usedStarterPack: Boolean(starterPack),
|
||||||
starterPackName:
|
starterPackName:
|
||||||
starterPack &&
|
starterPack &&
|
||||||
bsky.dangerousIsType<AppBskyGraphStarterpack.Record>(
|
bsky.isType(app.bsky.graph.starterpack, starterPack.record)
|
||||||
starterPack.record,
|
|
||||||
AppBskyGraphStarterpack.isRecord,
|
|
||||||
)
|
|
||||||
? starterPack.record.name
|
? starterPack.record.name
|
||||||
: undefined,
|
: undefined,
|
||||||
starterPackCreator: starterPack?.creator.did,
|
starterPackCreator: starterPack?.creator.did,
|
||||||
@@ -242,9 +233,8 @@ export function StepFinished() {
|
|||||||
}, [
|
}, [
|
||||||
ax,
|
ax,
|
||||||
queryClient,
|
queryClient,
|
||||||
agent,
|
|
||||||
appviewClient,
|
|
||||||
pdsClient,
|
pdsClient,
|
||||||
|
appviewClient,
|
||||||
dispatch,
|
dispatch,
|
||||||
onboardDispatch,
|
onboardDispatch,
|
||||||
activeStarterPack,
|
activeStarterPack,
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export function useAllListMembersQuery(uri?: string) {
|
|||||||
export async function getAllListMembers(client: Client, uri: string) {
|
export async function getAllListMembers(client: Client, uri: string) {
|
||||||
let hasMore = true
|
let hasMore = true
|
||||||
let cursor: string | undefined
|
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
|
// We want to cap this at 6 pages, just for anything weird happening with the api
|
||||||
let i = 0
|
let i = 0
|
||||||
while (hasMore && i < 6) {
|
while (hasMore && i < 6) {
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
import {type AppBskyActorProfile, type Un$Typed} from '@atproto/api'
|
|
||||||
import {TID} from '@atproto/common-web'
|
import {TID} from '@atproto/common-web'
|
||||||
import {type Client} from '@atproto/lex'
|
import {type Client} from '@atproto/lex'
|
||||||
import {PasswordSession} from '@atproto/lex-password-session'
|
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 {networkRetry} from '#/lib/async/retry'
|
||||||
import {
|
import {
|
||||||
@@ -21,7 +26,7 @@ import {
|
|||||||
} from '#/ageAssurance/data'
|
} from '#/ageAssurance/data'
|
||||||
import {unsafeGetAndComputeAgeAssurance} from '#/ageAssurance/state'
|
import {unsafeGetAndComputeAgeAssurance} from '#/ageAssurance/state'
|
||||||
import {features} from '#/analytics'
|
import {features} from '#/analytics'
|
||||||
import {type BskyAppAgent} from './bridge-agent'
|
import {type app} from '#/lexicons'
|
||||||
import {agentToPdsClient} from './clients'
|
import {agentToPdsClient} from './clients'
|
||||||
import {configureModerationForAccount} from './moderation'
|
import {configureModerationForAccount} from './moderation'
|
||||||
import {
|
import {
|
||||||
@@ -88,7 +93,7 @@ export async function createSessionBundleAndCreateAccount(
|
|||||||
const gates = features.refresh({strategy: 'prefer-fresh-gates'})
|
const gates = features.refresh({strategy: 'prefer-fresh-gates'})
|
||||||
configureModerationForAccount(bundle.agent, earlyAccount)
|
configureModerationForAccount(bundle.agent, earlyAccount)
|
||||||
|
|
||||||
const createdAt = new Date().toISOString()
|
const createdAt = toDatetimeString(new Date())
|
||||||
const birthdate = birthDate.toISOString()
|
const birthdate = birthDate.toISOString()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -104,18 +109,16 @@ export async function createSessionBundleAndCreateAccount(
|
|||||||
const aa = prefetchAgeAssuranceServerData({agent: bundle.agent})
|
const aa = prefetchAgeAssuranceServerData({agent: bundle.agent})
|
||||||
|
|
||||||
const isProd = Boolean(IS_PROD_SERVICE(service))
|
const isProd = Boolean(IS_PROD_SERVICE(service))
|
||||||
|
// Post-signup writes all target the account's own repo and actor store.
|
||||||
|
const pdsClient = agentToPdsClient(bundle.agent)
|
||||||
const postSignupTasks: Promise<unknown>[] = [
|
const postSignupTasks: Promise<unknown>[] = [
|
||||||
savePersonalDetails(bundle.agent, birthdate),
|
savePersonalDetails(pdsClient, birthDate),
|
||||||
initializeProfile(bundle.agent, {handle, createdAt, isProd}),
|
initializeProfile(pdsClient, {handle, createdAt, isProd}),
|
||||||
]
|
]
|
||||||
if (isProd) {
|
if (isProd) {
|
||||||
postSignupTasks.push(
|
postSignupTasks.push(
|
||||||
initializeSavedFeeds(bundle.agent),
|
initializeSavedFeeds(pdsClient),
|
||||||
restrictChatAfterAgeAssurance(
|
restrictChatAfterAgeAssurance(aa, pdsClient, earlyAccount.did),
|
||||||
aa,
|
|
||||||
agentToPdsClient(bundle.agent),
|
|
||||||
earlyAccount.did,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// Post-signup writes are not required to enter onboarding.
|
// Post-signup writes are not required to enter onboarding.
|
||||||
@@ -170,41 +173,41 @@ function snapshotNewAccount(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function savePersonalDetails(agent: BskyAppAgent, birthDate: string) {
|
function savePersonalDetails(client: Client, birthDate: Date) {
|
||||||
return retryPostSignupTask('set birthDate', 3, () =>
|
return retryPostSignupTask('set birthDate', 3, () =>
|
||||||
agent.setPersonalDetails({birthDate}),
|
client.call(setPersonalDetails, {birthDate}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializeProfile(
|
function initializeProfile(
|
||||||
agent: BskyAppAgent,
|
client: Client,
|
||||||
{
|
{
|
||||||
handle,
|
handle,
|
||||||
createdAt,
|
createdAt,
|
||||||
isProd,
|
isProd,
|
||||||
}: {
|
}: {
|
||||||
handle: string
|
handle: string
|
||||||
createdAt: string
|
createdAt: ReturnType<typeof toDatetimeString>
|
||||||
isProd: boolean
|
isProd: boolean
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
return retryPostSignupTask('set initial profile', 3, () =>
|
return retryPostSignupTask('set initial profile', 3, () =>
|
||||||
agent.upsertProfile(prev => {
|
client.call(upsertProfile, prev => {
|
||||||
const next: Un$Typed<AppBskyActorProfile.Record> = prev || {}
|
const next: Partial<app.bsky.actor.profile.Main> = prev || {}
|
||||||
if (isProd) {
|
if (isProd) {
|
||||||
next.displayName = handle
|
next.displayName = handle
|
||||||
next.createdAt = createdAt
|
next.createdAt = createdAt
|
||||||
} else {
|
} else {
|
||||||
next.createdAt = prev?.createdAt || new Date().toISOString()
|
next.createdAt = prev?.createdAt || toDatetimeString(new Date())
|
||||||
}
|
}
|
||||||
return next
|
return next
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializeSavedFeeds(agent: BskyAppAgent) {
|
function initializeSavedFeeds(client: Client) {
|
||||||
return retryPostSignupTask('set initial feeds', 1, () =>
|
return retryPostSignupTask('set initial feeds', 1, () =>
|
||||||
agent.overwriteSavedFeeds([
|
client.call(overwriteSavedFeeds, [
|
||||||
{...DISCOVER_SAVED_FEED, id: TID.nextStr()},
|
{...DISCOVER_SAVED_FEED, id: TID.nextStr()},
|
||||||
{...TIMELINE_SAVED_FEED, id: TID.nextStr()},
|
{...TIMELINE_SAVED_FEED, id: TID.nextStr()},
|
||||||
]),
|
]),
|
||||||
|
|||||||
Reference in New Issue
Block a user