[SDK] Migrate agent sugar to @bsky.app/sdk actions (#11382)
This commit is contained in:
@@ -16,7 +16,7 @@ import {Trans} from '@lingui/react/macro'
|
|||||||
import {retry} from '#/lib/async/retry'
|
import {retry} from '#/lib/async/retry'
|
||||||
import {wait} from '#/lib/async/wait'
|
import {wait} from '#/lib/async/wait'
|
||||||
import {parseLinkingUrl} from '#/lib/parseLinkingUrl'
|
import {parseLinkingUrl} from '#/lib/parseLinkingUrl'
|
||||||
import {useAgent, useSession} from '#/state/session'
|
import {useAppviewClient, useSession} from '#/state/session'
|
||||||
import {atoms as a, platform, useBreakpoints, useTheme} from '#/alf'
|
import {atoms as a, platform, useBreakpoints, useTheme} from '#/alf'
|
||||||
import {AgeAssuranceBadge} from '#/components/ageAssurance/AgeAssuranceBadge'
|
import {AgeAssuranceBadge} from '#/components/ageAssurance/AgeAssuranceBadge'
|
||||||
import {Button, ButtonText} from '#/components/Button'
|
import {Button, ButtonText} from '#/components/Button'
|
||||||
@@ -176,7 +176,7 @@ function Inner() {
|
|||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const agent = useAgent()
|
const appviewClient = useAppviewClient()
|
||||||
const polling = useRef(false)
|
const polling = useRef(false)
|
||||||
const unmounted = useRef(false)
|
const unmounted = useRef(false)
|
||||||
const [error, setError] = useState(false)
|
const [error, setError] = useState(false)
|
||||||
@@ -196,10 +196,10 @@ function Inner() {
|
|||||||
5,
|
5,
|
||||||
() => true,
|
() => true,
|
||||||
async () => {
|
async () => {
|
||||||
if (!agent.session) return
|
if (!appviewClient.did) return
|
||||||
if (unmounted.current) return
|
if (unmounted.current) return
|
||||||
|
|
||||||
const data = await refetchAgeAssuranceServerState({agent})
|
const data = await refetchAgeAssuranceServerState({appviewClient})
|
||||||
|
|
||||||
if (data?.state.status !== 'assured') {
|
if (data?.state.status !== 'assured') {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -214,7 +214,7 @@ function Inner() {
|
|||||||
)
|
)
|
||||||
.then(async data => {
|
.then(async data => {
|
||||||
if (!data) return
|
if (!data) return
|
||||||
if (!agent.session) return
|
if (!appviewClient.did) return
|
||||||
if (unmounted.current) return
|
if (unmounted.current) return
|
||||||
|
|
||||||
setSuccess(true)
|
setSuccess(true)
|
||||||
@@ -230,7 +230,7 @@ function Inner() {
|
|||||||
return () => {
|
return () => {
|
||||||
unmounted.current = true
|
unmounted.current = true
|
||||||
}
|
}
|
||||||
}, [ax, agent])
|
}, [ax, appviewClient])
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
+65
-40
@@ -7,6 +7,8 @@ import {
|
|||||||
AtpAgent,
|
AtpAgent,
|
||||||
type ChatBskyActorDeclaration,
|
type ChatBskyActorDeclaration,
|
||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
|
import {type Client} from '@atproto/lex'
|
||||||
|
import {getPreferences} from '@bsky.app/sdk'
|
||||||
import {createAsyncStoragePersister} from '@tanstack/query-async-storage-persister'
|
import {createAsyncStoragePersister} from '@tanstack/query-async-storage-persister'
|
||||||
import {focusManager, QueryClient, useQuery} from '@tanstack/react-query'
|
import {focusManager, QueryClient, useQuery} from '@tanstack/react-query'
|
||||||
import {persistQueryClient} from '@tanstack/react-query-persist-client'
|
import {persistQueryClient} from '@tanstack/react-query-persist-client'
|
||||||
@@ -21,7 +23,7 @@ import {
|
|||||||
snoozeBirthdateUpdateAllowedForDid,
|
snoozeBirthdateUpdateAllowedForDid,
|
||||||
} from '#/state/birthdate'
|
} from '#/state/birthdate'
|
||||||
import {fetchActorDeclarationRecord} from '#/state/queries/messages/actor-declaration'
|
import {fetchActorDeclarationRecord} from '#/state/queries/messages/actor-declaration'
|
||||||
import {useAgent, useSession} from '#/state/session'
|
import {useAppviewClient, usePdsClient, useSession} from '#/state/session'
|
||||||
import {DEVICE_SIGNALS_SUPPORTED} from '#/ageAssurance/const'
|
import {DEVICE_SIGNALS_SUPPORTED} from '#/ageAssurance/const'
|
||||||
import * as debug from '#/ageAssurance/debug'
|
import * as debug from '#/ageAssurance/debug'
|
||||||
import {logger} from '#/ageAssurance/logger'
|
import {logger} from '#/ageAssurance/logger'
|
||||||
@@ -37,6 +39,7 @@ import {
|
|||||||
} from '#/ageAssurance/util'
|
} from '#/ageAssurance/util'
|
||||||
import {IS_DEV} from '#/env'
|
import {IS_DEV} from '#/env'
|
||||||
import {useGeolocation} from '#/geolocation'
|
import {useGeolocation} from '#/geolocation'
|
||||||
|
import {app} from '#/lexicons'
|
||||||
import {device} from '#/storage'
|
import {device} from '#/storage'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -63,12 +66,6 @@ const [, cacheHydrationPromise] = persistQueryClient({
|
|||||||
persister,
|
persister,
|
||||||
})
|
})
|
||||||
|
|
||||||
export function getDidFromAgentSession(agent: AtpAgent) {
|
|
||||||
const sessionManager = agent.sessionManager
|
|
||||||
if (!sessionManager || !sessionManager.did) return
|
|
||||||
return sessionManager.did
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Optimistic data
|
* Optimistic data
|
||||||
*/
|
*/
|
||||||
@@ -187,7 +184,7 @@ export function useConfigQuery() {
|
|||||||
export function createServerStateQueryKey({did}: {did: string}) {
|
export function createServerStateQueryKey({did}: {did: string}) {
|
||||||
return ['serverState', did]
|
return ['serverState', did]
|
||||||
}
|
}
|
||||||
export async function getServerState({agent}: {agent: AtpAgent}) {
|
export async function getServerState({appviewClient}: {appviewClient: Client}) {
|
||||||
if (debug.enabled && debug.serverState)
|
if (debug.enabled && debug.serverState)
|
||||||
return debug.resolve(debug.serverState)
|
return debug.resolve(debug.serverState)
|
||||||
const geolocation = device.get(['mergedGeolocation'])
|
const geolocation = device.get(['mergedGeolocation'])
|
||||||
@@ -195,17 +192,21 @@ export async function getServerState({agent}: {agent: AtpAgent}) {
|
|||||||
logger.error(`getServerState: missing geolocation countryCode`)
|
logger.error(`getServerState: missing geolocation countryCode`)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
const {data} = await agent.app.bsky.ageassurance.getState({
|
const data = await appviewClient.call(app.bsky.ageassurance.getState, {
|
||||||
countryCode: geolocation.countryCode,
|
countryCode: geolocation.countryCode,
|
||||||
regionCode: geolocation.regionCode,
|
regionCode: geolocation.regionCode,
|
||||||
})
|
})
|
||||||
const did = getDidFromAgentSession(agent)
|
const did = appviewClient.did
|
||||||
if (data && did && createdAtCache.has(did)) {
|
if (data && did && createdAtCache.has(did)) {
|
||||||
/*
|
/*
|
||||||
* If account was just created, just use the local cache if available. On
|
* If account was just created, just use the local cache if available. On
|
||||||
* subsequent reloads, the server should have the correct value.
|
* subsequent reloads, the server should have the correct value. The cache
|
||||||
|
* holds ISO datetime strings (written from `new Date().toISOString()`), so
|
||||||
|
* assert the branded DatetimeString at this boundary.
|
||||||
*/
|
*/
|
||||||
data.metadata.accountCreatedAt = createdAtCache.get(did)
|
data.metadata.accountCreatedAt = createdAtCache.get(
|
||||||
|
did,
|
||||||
|
) as typeof data.metadata.accountCreatedAt
|
||||||
}
|
}
|
||||||
return data ?? null
|
return data ?? null
|
||||||
}
|
}
|
||||||
@@ -218,8 +219,12 @@ export function getServerStateFromCache({
|
|||||||
createServerStateQueryKey({did}),
|
createServerStateQueryKey({did}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
export async function prefetchServerState({agent}: {agent: AtpAgent}) {
|
export async function prefetchServerState({
|
||||||
const did = getDidFromAgentSession(agent)
|
appviewClient,
|
||||||
|
}: {
|
||||||
|
appviewClient: Client
|
||||||
|
}) {
|
||||||
|
const did = appviewClient.did
|
||||||
|
|
||||||
if (!did) return
|
if (!did) return
|
||||||
|
|
||||||
@@ -234,7 +239,7 @@ export async function prefetchServerState({agent}: {agent: AtpAgent}) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
logger.debug(`prefetchServerState: resolving...`)
|
logger.debug(`prefetchServerState: resolving...`)
|
||||||
const res = await networkRetry(3, () => getServerState({agent}))
|
const res = await networkRetry(3, () => getServerState({appviewClient}))
|
||||||
if (res) {
|
if (res) {
|
||||||
qc.setQueryData<AppBskyAgeassuranceGetState.OutputSchema>(qk, res)
|
qc.setQueryData<AppBskyAgeassuranceGetState.OutputSchema>(qk, res)
|
||||||
}
|
}
|
||||||
@@ -245,11 +250,15 @@ export async function prefetchServerState({agent}: {agent: AtpAgent}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export async function refetchServerState({agent}: {agent: AtpAgent}) {
|
export async function refetchServerState({
|
||||||
const did = getDidFromAgentSession(agent)
|
appviewClient,
|
||||||
|
}: {
|
||||||
|
appviewClient: Client
|
||||||
|
}) {
|
||||||
|
const did = appviewClient.did
|
||||||
if (!did) return
|
if (!did) return
|
||||||
logger.debug(`refetchServerState: fetching...`)
|
logger.debug(`refetchServerState: fetching...`)
|
||||||
const res = await networkRetry(3, () => getServerState({agent}))
|
const res = await networkRetry(3, () => getServerState({appviewClient}))
|
||||||
if (res) {
|
if (res) {
|
||||||
qc.setQueryData<AppBskyAgeassuranceGetState.OutputSchema>(
|
qc.setQueryData<AppBskyAgeassuranceGetState.OutputSchema>(
|
||||||
createServerStateQueryKey({did}),
|
createServerStateQueryKey({did}),
|
||||||
@@ -279,8 +288,8 @@ export function usePatchServerState() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
export function useServerStateQuery() {
|
export function useServerStateQuery() {
|
||||||
const agent = useAgent()
|
const appviewClient = useAppviewClient()
|
||||||
const did = getDidFromAgentSession(agent)
|
const did = appviewClient.did
|
||||||
const query = useQuery(
|
const query = useQuery(
|
||||||
{
|
{
|
||||||
enabled: !!did,
|
enabled: !!did,
|
||||||
@@ -290,7 +299,7 @@ export function useServerStateQuery() {
|
|||||||
},
|
},
|
||||||
queryKey: createServerStateQueryKey({did: did!}),
|
queryKey: createServerStateQueryKey({did: did!}),
|
||||||
async queryFn() {
|
async queryFn() {
|
||||||
return getServerState({agent})
|
return getServerState({appviewClient})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
qc,
|
qc,
|
||||||
@@ -342,15 +351,15 @@ export function createOtherRequiredDataQueryKey({did}: {did: string}) {
|
|||||||
return ['otherRequiredData', did]
|
return ['otherRequiredData', did]
|
||||||
}
|
}
|
||||||
async function getOtherRequiredData({
|
async function getOtherRequiredData({
|
||||||
agent,
|
accountClient,
|
||||||
}: {
|
}: {
|
||||||
agent: AtpAgent
|
accountClient: Client
|
||||||
}): Promise<OtherRequiredData> {
|
}): Promise<OtherRequiredData> {
|
||||||
if (debug.enabled) return debug.resolve(debug.otherRequiredData)
|
if (debug.enabled) return debug.resolve(debug.otherRequiredData)
|
||||||
const did = getDidFromAgentSession(agent)
|
const did = accountClient.did
|
||||||
const [prefs, actorDeclaration] = await Promise.all([
|
const [prefs, actorDeclaration] = await Promise.all([
|
||||||
agent.getPreferences(),
|
accountClient.call(getPreferences),
|
||||||
fetchActorDeclarationRecord({did, agent}),
|
fetchActorDeclarationRecord({did, client: accountClient}),
|
||||||
])
|
])
|
||||||
const data: OtherRequiredData = {
|
const data: OtherRequiredData = {
|
||||||
birthdate: prefs.birthDate ? prefs.birthDate.toISOString() : undefined,
|
birthdate: prefs.birthDate ? prefs.birthDate.toISOString() : undefined,
|
||||||
@@ -426,8 +435,12 @@ export function setOtherRequiredDataActorDeclarationCache({
|
|||||||
next,
|
next,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
export async function prefetchOtherRequiredData({agent}: {agent: AtpAgent}) {
|
export async function prefetchOtherRequiredData({
|
||||||
const did = getDidFromAgentSession(agent)
|
accountClient,
|
||||||
|
}: {
|
||||||
|
accountClient: Client
|
||||||
|
}) {
|
||||||
|
const did = accountClient.did
|
||||||
|
|
||||||
if (!did) return
|
if (!did) return
|
||||||
|
|
||||||
@@ -442,7 +455,9 @@ export async function prefetchOtherRequiredData({agent}: {agent: AtpAgent}) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
logger.debug(`prefetchOtherRequiredData: resolving...`)
|
logger.debug(`prefetchOtherRequiredData: resolving...`)
|
||||||
const res = await networkRetry(3, () => getOtherRequiredData({agent}))
|
const res = await networkRetry(3, () =>
|
||||||
|
getOtherRequiredData({accountClient}),
|
||||||
|
)
|
||||||
qc.setQueryData<OtherRequiredData>(qk, res)
|
qc.setQueryData<OtherRequiredData>(qk, res)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const e = err as Error
|
const e = err as Error
|
||||||
@@ -471,8 +486,8 @@ export function usePatchOtherRequiredData() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
export function useOtherRequiredDataQuery() {
|
export function useOtherRequiredDataQuery() {
|
||||||
const agent = useAgent()
|
const accountClient = usePdsClient()
|
||||||
const did = getDidFromAgentSession(agent)
|
const did = accountClient.did
|
||||||
return useQuery(
|
return useQuery(
|
||||||
{
|
{
|
||||||
enabled: !!did,
|
enabled: !!did,
|
||||||
@@ -482,7 +497,7 @@ export function useOtherRequiredDataQuery() {
|
|||||||
},
|
},
|
||||||
queryKey: createOtherRequiredDataQueryKey({did: did!}),
|
queryKey: createOtherRequiredDataQueryKey({did: did!}),
|
||||||
async queryFn() {
|
async queryFn() {
|
||||||
return getOtherRequiredData({agent})
|
return getOtherRequiredData({accountClient})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
qc,
|
qc,
|
||||||
@@ -577,8 +592,12 @@ export function setDeviceSignalsForRegion({
|
|||||||
prev => ({...prev, [regionKey]: signals}),
|
prev => ({...prev, [regionKey]: signals}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
export async function prefetchDeviceSignals({agent}: {agent: AtpAgent}) {
|
export async function prefetchDeviceSignals({
|
||||||
const did = getDidFromAgentSession(agent)
|
appviewClient,
|
||||||
|
}: {
|
||||||
|
appviewClient: Client
|
||||||
|
}) {
|
||||||
|
const did = appviewClient.did
|
||||||
if (!did) return
|
if (!did) return
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -613,8 +632,8 @@ export async function prefetchDeviceSignals({agent}: {agent: AtpAgent}) {
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
export function useDeviceSignalsQuery() {
|
export function useDeviceSignalsQuery() {
|
||||||
const agent = useAgent()
|
const appviewClient = useAppviewClient()
|
||||||
const did = getDidFromAgentSession(agent)
|
const did = appviewClient.did
|
||||||
const {data: config} = useConfigQuery()
|
const {data: config} = useConfigQuery()
|
||||||
const geolocation = useGeolocation()
|
const geolocation = useGeolocation()
|
||||||
/*
|
/*
|
||||||
@@ -659,13 +678,19 @@ export function useDeviceSignalsQuery() {
|
|||||||
/**
|
/**
|
||||||
* Helper to prefetch all age assurance data from the server.
|
* Helper to prefetch all age assurance data from the server.
|
||||||
*/
|
*/
|
||||||
export function prefetchAgeAssuranceServerData({agent}: {agent: AtpAgent}) {
|
export function prefetchAgeAssuranceServerData({
|
||||||
|
appviewClient,
|
||||||
|
accountClient,
|
||||||
|
}: {
|
||||||
|
appviewClient: Client
|
||||||
|
accountClient: Client
|
||||||
|
}) {
|
||||||
return Promise.allSettled([
|
return Promise.allSettled([
|
||||||
// config fetch initiated at the top of the App.platform.tsx files, awaited here
|
// config fetch initiated at the top of the App.platform.tsx files, awaited here
|
||||||
configPrefetchPromise,
|
configPrefetchPromise,
|
||||||
prefetchServerState({agent}),
|
prefetchServerState({appviewClient}),
|
||||||
prefetchOtherRequiredData({agent}),
|
prefetchOtherRequiredData({accountClient}),
|
||||||
prefetchDeviceSignals({agent}),
|
prefetchDeviceSignals({appviewClient}),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {Trans} from '@lingui/react/macro'
|
|||||||
|
|
||||||
import {retry} from '#/lib/async/retry'
|
import {retry} from '#/lib/async/retry'
|
||||||
import {wait} from '#/lib/async/wait'
|
import {wait} from '#/lib/async/wait'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAppviewClient} from '#/state/session'
|
||||||
import {atoms as a, useTheme, web} from '#/alf'
|
import {atoms as a, useTheme, web} from '#/alf'
|
||||||
import {AgeAssuranceBadge} from '#/components/ageAssurance/AgeAssuranceBadge'
|
import {AgeAssuranceBadge} from '#/components/ageAssurance/AgeAssuranceBadge'
|
||||||
import {Button, ButtonText} from '#/components/Button'
|
import {Button, ButtonText} from '#/components/Button'
|
||||||
@@ -84,7 +84,7 @@ export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
|
|||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const agent = useAgent()
|
const appviewClient = useAppviewClient()
|
||||||
const polling = useRef(false)
|
const polling = useRef(false)
|
||||||
const unmounted = useRef(false)
|
const unmounted = useRef(false)
|
||||||
const control = useAgeAssuranceRedirectDialogControl()
|
const control = useAgeAssuranceRedirectDialogControl()
|
||||||
@@ -104,10 +104,10 @@ export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
|
|||||||
5,
|
5,
|
||||||
() => true,
|
() => true,
|
||||||
async () => {
|
async () => {
|
||||||
if (!agent.session) return
|
if (!appviewClient.did) return
|
||||||
if (unmounted.current) return
|
if (unmounted.current) return
|
||||||
|
|
||||||
const data = await refetchAgeAssuranceServerState({agent})
|
const data = await refetchAgeAssuranceServerState({appviewClient})
|
||||||
|
|
||||||
if (data?.state.status !== 'assured') {
|
if (data?.state.status !== 'assured') {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -122,7 +122,7 @@ export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
|
|||||||
)
|
)
|
||||||
.then(async data => {
|
.then(async data => {
|
||||||
if (!data) return
|
if (!data) return
|
||||||
if (!agent.session) return
|
if (!appviewClient.did) return
|
||||||
if (unmounted.current) return
|
if (unmounted.current) return
|
||||||
|
|
||||||
setSuccess(true)
|
setSuccess(true)
|
||||||
@@ -138,7 +138,7 @@ export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
|
|||||||
return () => {
|
return () => {
|
||||||
unmounted.current = true
|
unmounted.current = true
|
||||||
}
|
}
|
||||||
}, [ax, agent, control])
|
}, [ax, appviewClient, control])
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -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,12 +1,12 @@
|
|||||||
import {useEffect} from 'react'
|
import {useEffect} from 'react'
|
||||||
import {type Agent, AppBskyActorDefs, asPredicate} from '@atproto/api'
|
import {getPreferences, updateLiveEventPreferences} from '@bsky.app/sdk'
|
||||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
preferencesQueryKey,
|
preferencesQueryKey,
|
||||||
usePreferencesQuery,
|
usePreferencesQuery,
|
||||||
} from '#/state/queries/preferences'
|
} from '#/state/queries/preferences'
|
||||||
import {useAgent} from '#/state/session'
|
import {usePdsClient} from '#/state/session'
|
||||||
import {useAnalytics} from '#/analytics'
|
import {useAnalytics} from '#/analytics'
|
||||||
import * as env from '#/env'
|
import * as env from '#/env'
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
@@ -14,10 +14,11 @@ import {
|
|||||||
type LiveEventFeed,
|
type LiveEventFeed,
|
||||||
type LiveEventFeedMetricContext,
|
type LiveEventFeedMetricContext,
|
||||||
} from '#/features/liveEvents/types'
|
} from '#/features/liveEvents/types'
|
||||||
|
import {type app} from '#/lexicons'
|
||||||
|
|
||||||
export type LiveEventPreferencesAction = Parameters<
|
export type LiveEventPreferencesAction = Parameters<
|
||||||
Agent['updateLiveEventPreferences']
|
typeof updateLiveEventPreferences
|
||||||
>[0] & {
|
>[1] & {
|
||||||
/**
|
/**
|
||||||
* Flag that is internal to this hook, do not set when updating prefs
|
* Flag that is internal to this hook, do not set when updating prefs
|
||||||
*/
|
*/
|
||||||
@@ -38,7 +39,7 @@ export function useLiveEventPreferences() {
|
|||||||
|
|
||||||
function useWebOnlyDebugLiveEventPreferences() {
|
function useWebOnlyDebugLiveEventPreferences() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const pdsClient = usePdsClient()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (env.IS_DEV && IS_WEB && typeof window !== 'undefined') {
|
if (env.IS_DEV && IS_WEB && typeof window !== 'undefined') {
|
||||||
@@ -46,14 +47,14 @@ function useWebOnlyDebugLiveEventPreferences() {
|
|||||||
window.__updateLiveEventPreferences = async (
|
window.__updateLiveEventPreferences = async (
|
||||||
action: LiveEventPreferencesAction,
|
action: LiveEventPreferencesAction,
|
||||||
) => {
|
) => {
|
||||||
await agent.updateLiveEventPreferences(action)
|
await pdsClient.call(updateLiveEventPreferences, action)
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [agent, queryClient])
|
}, [pdsClient, queryClient])
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useUpdateLiveEventPreferences(props: {
|
export function useUpdateLiveEventPreferences(props: {
|
||||||
@@ -65,10 +66,10 @@ export function useUpdateLiveEventPreferences(props: {
|
|||||||
}) {
|
}) {
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const pdsClient = usePdsClient()
|
||||||
|
|
||||||
return useMutation<
|
return useMutation<
|
||||||
AppBskyActorDefs.LiveEventPreferences,
|
app.bsky.actor.defs.LiveEventPreferences,
|
||||||
Error,
|
Error,
|
||||||
LiveEventPreferencesAction,
|
LiveEventPreferencesAction,
|
||||||
{undoAction: LiveEventPreferencesAction | null}
|
{undoAction: LiveEventPreferencesAction | null}
|
||||||
@@ -108,10 +109,14 @@ export function useUpdateLiveEventPreferences(props: {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mutationFn: async action => {
|
mutationFn: async action => {
|
||||||
const updated = await agent.updateLiveEventPreferences(action)
|
/*
|
||||||
const prefs = updated.find(p =>
|
* The SDK action returns void, so after applying the update we read the
|
||||||
asPredicate(AppBskyActorDefs.validateLiveEventPreferences)(p),
|
* fresh, interpreted preferences back to obtain the updated
|
||||||
)
|
* `liveEventPreferences` (the SDK extracts it from the raw prefs array for
|
||||||
|
* us, replacing the old `asPredicate(...).find(...)` lookup).
|
||||||
|
*/
|
||||||
|
await pdsClient.call(updateLiveEventPreferences, action)
|
||||||
|
const {liveEventPreferences: prefs} = await pdsClient.call(getPreferences)
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'hideFeed':
|
case 'hideFeed':
|
||||||
@@ -138,7 +143,7 @@ export function useUpdateLiveEventPreferences(props: {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'toggleHideAllFeeds': {
|
case 'toggleHideAllFeeds': {
|
||||||
if (prefs!.hideAllFeeds) {
|
if (prefs.hideAllFeeds) {
|
||||||
ax.metric('liveEvents:hideAllFeedBanners', {
|
ax.metric('liveEvents:hideAllFeedBanners', {
|
||||||
context: props.metricContext,
|
context: props.metricContext,
|
||||||
})
|
})
|
||||||
@@ -156,7 +161,7 @@ export function useUpdateLiveEventPreferences(props: {
|
|||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
})
|
})
|
||||||
|
|
||||||
return prefs!
|
return prefs
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import {useMemo, useState} from 'react'
|
import {useMemo, useState} from 'react'
|
||||||
import {type TextStyle, View, type ViewStyle} from 'react-native'
|
import {type TextStyle, View, type ViewStyle} from 'react-native'
|
||||||
|
import {setInterestsPref} 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'
|
||||||
@@ -23,7 +24,7 @@ import {createGetSuggestedUsersForDiscoverQueryKey} from '#/state/queries/trendi
|
|||||||
import {createGetSuggestedUsersForExploreQueryKey} from '#/state/queries/trending/useGetSuggestedUsersForExploreQuery'
|
import {createGetSuggestedUsersForExploreQueryKey} from '#/state/queries/trending/useGetSuggestedUsersForExploreQuery'
|
||||||
import {createGetSuggestedUsersForSeeMoreQueryKey} from '#/state/queries/trending/useGetSuggestedUsersForSeeMoreQuery'
|
import {createGetSuggestedUsersForSeeMoreQueryKey} from '#/state/queries/trending/useGetSuggestedUsersForSeeMoreQuery'
|
||||||
import {createSuggestedStarterPacksQueryKey} from '#/state/queries/useSuggestedStarterPacksQuery'
|
import {createSuggestedStarterPacksQueryKey} from '#/state/queries/useSuggestedStarterPacksQuery'
|
||||||
import {useAgent} from '#/state/session'
|
import {usePdsClient} from '#/state/session'
|
||||||
import {atoms as a, useGutters, useTheme} from '#/alf'
|
import {atoms as a, useGutters, useTheme} from '#/alf'
|
||||||
import {Admonition} from '#/components/Admonition'
|
import {Admonition} from '#/components/Admonition'
|
||||||
import {Divider} from '#/components/Divider'
|
import {Divider} from '#/components/Divider'
|
||||||
@@ -88,7 +89,7 @@ function Inner({
|
|||||||
setIsSaving: (isSaving: boolean) => void
|
setIsSaving: (isSaving: boolean) => void
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const agent = useAgent()
|
const pdsClient = usePdsClient()
|
||||||
const qc = useQueryClient()
|
const qc = useQueryClient()
|
||||||
const interestsDisplayNames = useInterestsDisplayNames()
|
const interestsDisplayNames = useInterestsDisplayNames()
|
||||||
const preselectedInterests = useMemo(
|
const preselectedInterests = useMemo(
|
||||||
@@ -110,7 +111,7 @@ function Inner({
|
|||||||
setIsSaving(true)
|
setIsSaving(true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await agent.setInterestsPref({tags: interests})
|
await pdsClient.call(setInterestsPref, {tags: interests})
|
||||||
qc.setQueriesData(
|
qc.setQueriesData(
|
||||||
{queryKey: preferencesQueryKey},
|
{queryKey: preferencesQueryKey},
|
||||||
(old?: UsePreferencesQueryResponse) => {
|
(old?: UsePreferencesQueryResponse) => {
|
||||||
@@ -157,7 +158,7 @@ function Inner({
|
|||||||
setIsSaving(false)
|
setIsSaving(false)
|
||||||
}
|
}
|
||||||
}, 1500)
|
}, 1500)
|
||||||
}, [_, agent, setIsSaving, qc, preselectedInterests])
|
}, [_, pdsClient, setIsSaving, qc, preselectedInterests])
|
||||||
|
|
||||||
const onChangeInterests = async (interests: string[]) => {
|
const onChangeInterests = async (interests: string[]) => {
|
||||||
setInterests(interests)
|
setInterests(interests)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import {useState} from 'react'
|
|||||||
import {Alert, LayoutAnimation, Linking, Pressable, View} from 'react-native'
|
import {Alert, LayoutAnimation, Linking, Pressable, View} from 'react-native'
|
||||||
import {useReducedMotion} from 'react-native-reanimated'
|
import {useReducedMotion} from 'react-native-reanimated'
|
||||||
import {type AppBskyActorDefs, moderateProfile} from '@atproto/api'
|
import {type AppBskyActorDefs, moderateProfile} from '@atproto/api'
|
||||||
|
import {removeNuxs} from '@bsky.app/sdk'
|
||||||
import {Trans, useLingui} from '@lingui/react/macro'
|
import {Trans, useLingui} from '@lingui/react/macro'
|
||||||
import {useNavigation} from '@react-navigation/native'
|
import {useNavigation} from '@react-navigation/native'
|
||||||
import {type NativeStackScreenProps} from '@react-navigation/native-stack'
|
import {type NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||||
@@ -21,7 +22,7 @@ import {clearStorage} from '#/state/persisted'
|
|||||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {useDeleteActorDeclaration} from '#/state/queries/messages/actor-declaration'
|
import {useDeleteActorDeclaration} from '#/state/queries/messages/actor-declaration'
|
||||||
import {useProfileQuery, useProfilesQuery} from '#/state/queries/profile'
|
import {useProfileQuery, useProfilesQuery} from '#/state/queries/profile'
|
||||||
import {useAgent} from '#/state/session'
|
import {usePdsClient} from '#/state/session'
|
||||||
import {type SessionAccount, useSession, useSessionApi} from '#/state/session'
|
import {type SessionAccount, useSession, useSessionApi} from '#/state/session'
|
||||||
import {useOnboardingDispatch} from '#/state/shell'
|
import {useOnboardingDispatch} from '#/state/shell'
|
||||||
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
||||||
@@ -385,7 +386,7 @@ function ProfilePreview({
|
|||||||
|
|
||||||
function DevOptions() {
|
function DevOptions() {
|
||||||
const {t: l} = useLingui()
|
const {t: l} = useLingui()
|
||||||
const agent = useAgent()
|
const pdsClient = usePdsClient()
|
||||||
const [override, setOverride] = useStorage(device, [
|
const [override, setOverride] = useStorage(device, [
|
||||||
'policyUpdateDebugOverride',
|
'policyUpdateDebugOverride',
|
||||||
])
|
])
|
||||||
@@ -560,7 +561,7 @@ function DevOptions() {
|
|||||||
<Button
|
<Button
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
device.set([PolicyUpdate202508], false)
|
device.set([PolicyUpdate202508], false)
|
||||||
void agent.bskyAppRemoveNuxs([PolicyUpdate202508])
|
void pdsClient.call(removeNuxs, [PolicyUpdate202508])
|
||||||
Toast.show(`Done`, {
|
Toast.show(`Done`, {
|
||||||
type: 'info',
|
type: 'info',
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import {useMemo} from 'react'
|
import {useMemo} from 'react'
|
||||||
|
import {setPersonalDetails} from '@bsky.app/sdk'
|
||||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {restrictChatSettings} from '#/state/queries/messages/restrictChatSettings'
|
import {restrictChatSettings} from '#/state/queries/messages/restrictChatSettings'
|
||||||
import {preferencesQueryKey} from '#/state/queries/preferences'
|
import {preferencesQueryKey} from '#/state/queries/preferences'
|
||||||
import {useAgent, usePdsClient, useSession} from '#/state/session'
|
import {usePdsClient, useSession} from '#/state/session'
|
||||||
import {usePatchAgeAssuranceOtherRequiredData} from '#/ageAssurance'
|
import {usePatchAgeAssuranceOtherRequiredData} from '#/ageAssurance'
|
||||||
import {isUnderAge} from '#/ageAssurance/util'
|
import {isUnderAge} from '#/ageAssurance/util'
|
||||||
import {IS_DEV} from '#/env'
|
import {IS_DEV} from '#/env'
|
||||||
@@ -54,14 +55,14 @@ export function useIsBirthdateUpdateAllowed() {
|
|||||||
|
|
||||||
export function useBirthdateMutation() {
|
export function useBirthdateMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const {currentAccount} = useSession()
|
||||||
const pdsClient = usePdsClient()
|
const pdsClient = usePdsClient()
|
||||||
const patchOtherRequiredData = usePatchAgeAssuranceOtherRequiredData()
|
const patchOtherRequiredData = usePatchAgeAssuranceOtherRequiredData()
|
||||||
|
|
||||||
return useMutation<void, unknown, {birthDate: Date}>({
|
return useMutation<void, unknown, {birthDate: Date}>({
|
||||||
mutationFn: async ({birthDate}: {birthDate: Date}) => {
|
mutationFn: async ({birthDate}: {birthDate: Date}) => {
|
||||||
const bday = birthDate.toISOString()
|
const bday = birthDate.toISOString()
|
||||||
await agent.setPersonalDetails({birthDate: bday})
|
await pdsClient.call(setPersonalDetails, {birthDate})
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
@@ -80,7 +81,9 @@ export function useBirthdateMutation() {
|
|||||||
* birthdate, which may change the user's age assurance access level.
|
* birthdate, which may change the user's age assurance access level.
|
||||||
*/
|
*/
|
||||||
void patchOtherRequiredData({birthdate: bday})
|
void patchOtherRequiredData({birthdate: bday})
|
||||||
snoozeBirthdateUpdateAllowedForDid(agent.sessionManager.did!)
|
if (currentAccount) {
|
||||||
|
snoozeBirthdateUpdateAllowedForDid(currentAccount.did)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import {type AppBskyLabelerDefs} from '@atproto/api'
|
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 {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
||||||
import {z} from 'zod'
|
import {z} from 'zod'
|
||||||
|
|
||||||
@@ -9,7 +11,7 @@ import {
|
|||||||
usePreferencesQuery,
|
usePreferencesQuery,
|
||||||
} from '#/state/queries/preferences'
|
} from '#/state/queries/preferences'
|
||||||
import {createQueryKey} from '#/state/queries/util'
|
import {createQueryKey} from '#/state/queries/util'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAgent, usePdsClient} from '#/state/session'
|
||||||
|
|
||||||
const labelerInfoQueryKeyRoot = 'labeler-info'
|
const labelerInfoQueryKeyRoot = 'labeler-info'
|
||||||
export const labelerInfoQueryKey = (did: string) => [
|
export const labelerInfoQueryKey = (did: string) => [
|
||||||
@@ -78,11 +80,13 @@ export function useLabelersDetailedInfoQuery({dids}: {dids: string[]}) {
|
|||||||
|
|
||||||
export function useRemoveLabelersMutation() {
|
export function useRemoveLabelersMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
async mutationFn({dids}: {dids: string[]}) {
|
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() {
|
async onSuccess() {
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
@@ -95,6 +99,7 @@ export function useRemoveLabelersMutation() {
|
|||||||
export function useLabelerSubscriptionMutation() {
|
export function useLabelerSubscriptionMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
|
const pdsClient = usePdsClient()
|
||||||
const preferences = usePreferencesQuery()
|
const preferences = usePreferencesQuery()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
@@ -136,7 +141,11 @@ export function useLabelerSubscriptionMutation() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (invalidLabelers.length) {
|
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) {
|
if (subscribe) {
|
||||||
@@ -144,9 +153,9 @@ export function useLabelerSubscriptionMutation() {
|
|||||||
if (labelerCount >= MAX_LABELERS) {
|
if (labelerCount >= MAX_LABELERS) {
|
||||||
throw new Error('MAX_LABELERS')
|
throw new Error('MAX_LABELERS')
|
||||||
}
|
}
|
||||||
await agent.addLabeler(did)
|
await pdsClient.call(addLabeler, did as DidString)
|
||||||
} else {
|
} else {
|
||||||
await agent.removeLabeler(did)
|
await pdsClient.call(removeLabeler, did as DidString)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async onSuccess() {
|
async onSuccess() {
|
||||||
|
|||||||
@@ -1,22 +1,27 @@
|
|||||||
|
import {type AtUriString} from '@atproto/syntax'
|
||||||
|
import {deleteLike, like} from '@bsky.app/sdk'
|
||||||
import {useMutation} from '@tanstack/react-query'
|
import {useMutation} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {useAgent} from '#/state/session'
|
import {usePdsClient} from '#/state/session'
|
||||||
|
|
||||||
export function useLikeMutation() {
|
export function useLikeMutation() {
|
||||||
const agent = useAgent()
|
const pdsClient = usePdsClient()
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async ({uri, cid}: {uri: string; cid: string}) => {
|
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}
|
return {uri: res.uri}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useUnlikeMutation() {
|
export function useUnlikeMutation() {
|
||||||
const agent = useAgent()
|
const pdsClient = usePdsClient()
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async ({uri}: {uri: string}) => {
|
mutationFn: async ({uri}: {uri: string}) => {
|
||||||
await agent.deleteLike(uri)
|
await pdsClient.call(deleteLike, uri as AtUriString)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
+12
-14
@@ -6,6 +6,12 @@ import {
|
|||||||
type AtUriString,
|
type AtUriString,
|
||||||
toDatetimeString,
|
toDatetimeString,
|
||||||
} from '@atproto/syntax'
|
} from '@atproto/syntax'
|
||||||
|
import {
|
||||||
|
blockActorList,
|
||||||
|
muteActorList,
|
||||||
|
unblockActorList,
|
||||||
|
unmuteActorList,
|
||||||
|
} from '@bsky.app/sdk'
|
||||||
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
||||||
import chunk from 'lodash.chunk'
|
import chunk from 'lodash.chunk'
|
||||||
|
|
||||||
@@ -13,12 +19,7 @@ import {uploadBlob} from '#/lib/api'
|
|||||||
import {until} from '#/lib/async/until'
|
import {until} from '#/lib/async/until'
|
||||||
import {type ImageMeta} from '#/state/gallery'
|
import {type ImageMeta} from '#/state/gallery'
|
||||||
import {STALE} from '#/state/queries'
|
import {STALE} from '#/state/queries'
|
||||||
import {
|
import {useAppviewClient, usePdsClient, useSession} from '#/state/session'
|
||||||
useAgent,
|
|
||||||
useAppviewClient,
|
|
||||||
usePdsClient,
|
|
||||||
useSession,
|
|
||||||
} from '#/state/session'
|
|
||||||
import {app, com} from '#/lexicons'
|
import {app, com} from '#/lexicons'
|
||||||
import {FEED_INFO_RQKEY_ROOT} from './feed'
|
import {FEED_INFO_RQKEY_ROOT} from './feed'
|
||||||
import {invalidate as invalidateMyLists} from './my-lists'
|
import {invalidate as invalidateMyLists} from './my-lists'
|
||||||
@@ -255,15 +256,13 @@ export function useListDeleteMutation() {
|
|||||||
|
|
||||||
export function useListMuteMutation() {
|
export function useListMuteMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
|
||||||
const appviewClient = useAppviewClient()
|
const appviewClient = useAppviewClient()
|
||||||
return useMutation<void, Error, {uri: string; mute: boolean}>({
|
return useMutation<void, Error, {uri: string; mute: boolean}>({
|
||||||
mutationFn: async ({uri, mute}) => {
|
mutationFn: async ({uri, mute}) => {
|
||||||
// `muteModList`/`unmuteModList` are preference writes, migrated in wave B
|
|
||||||
if (mute) {
|
if (mute) {
|
||||||
await agent.muteModList(uri)
|
await appviewClient.call(muteActorList, {list: uri as AtUriString})
|
||||||
} else {
|
} else {
|
||||||
await agent.unmuteModList(uri)
|
await appviewClient.call(unmuteActorList, {list: uri as AtUriString})
|
||||||
}
|
}
|
||||||
|
|
||||||
await whenAppViewReady(appviewClient, uri, v => {
|
await whenAppViewReady(appviewClient, uri, v => {
|
||||||
@@ -280,15 +279,14 @@ export function useListMuteMutation() {
|
|||||||
|
|
||||||
export function useListBlockMutation() {
|
export function useListBlockMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
|
||||||
const appviewClient = useAppviewClient()
|
const appviewClient = useAppviewClient()
|
||||||
|
const pdsClient = usePdsClient()
|
||||||
return useMutation<void, Error, {uri: string; block: boolean}>({
|
return useMutation<void, Error, {uri: string; block: boolean}>({
|
||||||
mutationFn: async ({uri, block}) => {
|
mutationFn: async ({uri, block}) => {
|
||||||
// `blockModList`/`unblockModList` write a block record, migrated in wave B
|
|
||||||
if (block) {
|
if (block) {
|
||||||
await agent.blockModList(uri)
|
await pdsClient.call(blockActorList, {list: uri as AtUriString})
|
||||||
} else {
|
} else {
|
||||||
await agent.unblockModList(uri)
|
await pdsClient.call(unblockActorList, {list: uri as AtUriString})
|
||||||
}
|
}
|
||||||
|
|
||||||
await whenAppViewReady(appviewClient, uri, v => {
|
await whenAppViewReady(appviewClient, uri, v => {
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
import type AtpAgent from '@atproto/api'
|
import {type AppBskyActorDefs} from '@atproto/api'
|
||||||
import {
|
import {type Client} from '@atproto/lex'
|
||||||
type AppBskyActorDefs,
|
|
||||||
type ChatBskyActorDeclaration,
|
|
||||||
} from '@atproto/api'
|
|
||||||
import {type DidString} from '@atproto/syntax'
|
import {type DidString} from '@atproto/syntax'
|
||||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {usePdsClient, useSession} from '#/state/session'
|
import {usePdsClient, useSession} from '#/state/session'
|
||||||
import {resolveAllowGroupInvites} from '#/components/dms/util'
|
import {resolveAllowGroupInvites} from '#/components/dms/util'
|
||||||
import {com} from '#/lexicons'
|
import {chat, com} from '#/lexicons'
|
||||||
import {RQKEY as PROFILE_RKEY} from '../profile'
|
import {RQKEY as PROFILE_RKEY} from '../profile'
|
||||||
|
|
||||||
export function useUpdateActorDeclaration({
|
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({
|
export async function fetchActorDeclarationRecord({
|
||||||
agent,
|
client,
|
||||||
did,
|
did,
|
||||||
}: {
|
}: {
|
||||||
agent: AtpAgent
|
client: Client
|
||||||
did?: string
|
did?: string
|
||||||
}) {
|
}) {
|
||||||
if (!did) return
|
if (!did) return
|
||||||
const res = await agent.com.atproto.repo
|
const res = await client
|
||||||
.getRecord({
|
.get(chat.bsky.actor.declaration, {repo: did as DidString, rkey: 'self'})
|
||||||
repo: did,
|
|
||||||
collection: 'chat.bsky.actor.declaration',
|
|
||||||
rkey: 'self',
|
|
||||||
})
|
|
||||||
.catch(_e => undefined)
|
.catch(_e => undefined)
|
||||||
return res?.data.value as ChatBskyActorDeclaration.Main
|
return res?.value
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import {removeNuxs, upsertNux} from '@bsky.app/sdk'
|
||||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {type AppNux, type Nux} from '#/state/queries/nuxs/definitions'
|
import {type AppNux, type Nux} from '#/state/queries/nuxs/definitions'
|
||||||
@@ -6,7 +7,8 @@ import {
|
|||||||
preferencesQueryKey,
|
preferencesQueryKey,
|
||||||
usePreferencesQuery,
|
usePreferencesQuery,
|
||||||
} from '#/state/queries/preferences'
|
} 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'
|
export {Nux} from '#/state/queries/nuxs/definitions'
|
||||||
|
|
||||||
@@ -42,11 +44,11 @@ export function useNuxs():
|
|||||||
|
|
||||||
// if (__DEV__) {
|
// if (__DEV__) {
|
||||||
// const queryClient = useQueryClient()
|
// const queryClient = useQueryClient()
|
||||||
// const agent = useAgent()
|
// const pdsClient = usePdsClient()
|
||||||
|
|
||||||
// // @ts-ignore
|
// // @ts-ignore
|
||||||
// window.clearNux = async (ids: string[]) => {
|
// window.clearNux = async (ids: string[]) => {
|
||||||
// await agent.bskyAppRemoveNuxs(ids)
|
// await pdsClient.call(removeNuxs, ids)
|
||||||
// // triggers a refetch
|
// // triggers a refetch
|
||||||
// await queryClient.invalidateQueries({
|
// await queryClient.invalidateQueries({
|
||||||
// queryKey: preferencesQueryKey,
|
// queryKey: preferencesQueryKey,
|
||||||
@@ -97,12 +99,19 @@ export function useNux<T extends Nux>(
|
|||||||
|
|
||||||
export function useSaveNux() {
|
export function useSaveNux() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const pdsClient = usePdsClient()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
retry: 3,
|
retry: 3,
|
||||||
mutationFn: async (nux: AppNux) => {
|
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
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
@@ -113,12 +122,12 @@ export function useSaveNux() {
|
|||||||
|
|
||||||
export function useResetNuxs() {
|
export function useResetNuxs() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const pdsClient = usePdsClient()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
retry: 3,
|
retry: 3,
|
||||||
mutationFn: async (ids: string[]) => {
|
mutationFn: async (ids: string[]) => {
|
||||||
await agent.bskyAppRemoveNuxs(ids)
|
await pdsClient.call(removeNuxs, ids)
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {useMutation, useQueryClient} from '@tanstack/react-query'
|
|||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
|
import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
|
||||||
import * as Toast from '#/components/Toast'
|
import * as Toast from '#/components/Toast'
|
||||||
import {app} from '#/lexicons'
|
import {app, type com} from '#/lexicons'
|
||||||
import {updatePostShadow} from '../cache/post-shadow'
|
import {updatePostShadow} from '../cache/post-shadow'
|
||||||
import {useAppviewClient, useSession} from '../session'
|
import {useAppviewClient, useSession} from '../session'
|
||||||
import {useProfileUpdateMutation} from './profile'
|
import {useProfileUpdateMutation} from './profile'
|
||||||
@@ -47,7 +47,11 @@ export function usePinnedPostMutation() {
|
|||||||
profile,
|
profile,
|
||||||
updates: existing => {
|
updates: existing => {
|
||||||
existing.pinnedPost = pinCurrentPost
|
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
|
: undefined
|
||||||
return existing
|
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 {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {preferencesQueryKey} from '#/state/queries/preferences'
|
import {preferencesQueryKey} from '#/state/queries/preferences'
|
||||||
import {useAgent} from '#/state/session'
|
import {usePdsClient} from '#/state/session'
|
||||||
|
import {type app} from '#/lexicons'
|
||||||
|
|
||||||
export function usePostInteractionSettingsMutation({
|
export function usePostInteractionSettingsMutation({
|
||||||
onError,
|
onError,
|
||||||
@@ -12,10 +13,10 @@ export function usePostInteractionSettingsMutation({
|
|||||||
onSettled?: () => void
|
onSettled?: () => void
|
||||||
} = {}) {
|
} = {}) {
|
||||||
const qc = useQueryClient()
|
const qc = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
return useMutation({
|
return useMutation({
|
||||||
async mutationFn(props: AppBskyActorDefs.PostInteractionSettingsPref) {
|
async mutationFn(props: app.bsky.actor.defs.PostInteractionSettingsPref) {
|
||||||
await agent.setPostInteractionSettings(props)
|
await client.call(setPostInteractionSettings, props)
|
||||||
},
|
},
|
||||||
async onSuccess() {
|
async onSuccess() {
|
||||||
await qc.invalidateQueries({
|
await qc.invalidateQueries({
|
||||||
|
|||||||
+39
-17
@@ -1,5 +1,7 @@
|
|||||||
import {useCallback} from 'react'
|
import {useCallback} from 'react'
|
||||||
import {type AppBskyActorDefs, type AppBskyFeedDefs, AtUri} from '@atproto/api'
|
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 {
|
import {
|
||||||
type QueryClient,
|
type QueryClient,
|
||||||
useMutation,
|
useMutation,
|
||||||
@@ -10,10 +12,16 @@ import {
|
|||||||
import {useToggleMutationQueue} from '#/lib/hooks/useToggleMutationQueue'
|
import {useToggleMutationQueue} from '#/lib/hooks/useToggleMutationQueue'
|
||||||
import {updatePostShadow} from '#/state/cache/post-shadow'
|
import {updatePostShadow} from '#/state/cache/post-shadow'
|
||||||
import {type Shadow} from '#/state/cache/types'
|
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 * as userActionHistory from '#/state/userActionHistory'
|
||||||
import {useAnalytics} from '#/analytics'
|
import {useAnalytics} from '#/analytics'
|
||||||
import {type Metrics, toClout} from '#/analytics/metrics'
|
import {type Metrics, toClout} from '#/analytics/metrics'
|
||||||
|
import {app} from '#/lexicons'
|
||||||
import {useIsThreadMuted, useSetThreadMute} from '../cache/thread-mutes'
|
import {useIsThreadMuted, useSetThreadMute} from '../cache/thread-mutes'
|
||||||
import {findProfileQueryData} from './profile'
|
import {findProfileQueryData} from './profile'
|
||||||
|
|
||||||
@@ -184,7 +192,7 @@ function usePostLikeMutation(
|
|||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const postAuthor = post.author
|
const postAuthor = post.author
|
||||||
const agent = useAgent()
|
const pdsClient = usePdsClient()
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
return useMutation<
|
return useMutation<
|
||||||
{uri: string}, // responds with the uri of the like
|
{uri: string}, // responds with the uri of the like
|
||||||
@@ -215,7 +223,11 @@ function usePostLikeMutation(
|
|||||||
: undefined,
|
: undefined,
|
||||||
feedDescriptor: feedDescriptor,
|
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'],
|
logContext: Metrics['post:unlike']['logContext'],
|
||||||
post: Shadow<AppBskyFeedDefs.PostView>,
|
post: Shadow<AppBskyFeedDefs.PostView>,
|
||||||
) {
|
) {
|
||||||
const agent = useAgent()
|
const pdsClient = usePdsClient()
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
return useMutation<void, Error, {postUri: string; likeUri: string}>({
|
return useMutation<void, Error, {postUri: string; likeUri: string}>({
|
||||||
mutationFn: ({postUri, likeUri}) => {
|
mutationFn: ({postUri, likeUri}) => {
|
||||||
@@ -235,7 +247,7 @@ function usePostUnlikeMutation(
|
|||||||
logContext,
|
logContext,
|
||||||
feedDescriptor,
|
feedDescriptor,
|
||||||
})
|
})
|
||||||
return agent.deleteLike(likeUri)
|
return pdsClient.call(deleteLike, likeUri as AtUriString)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -309,7 +321,7 @@ function usePostRepostMutation(
|
|||||||
logContext: Metrics['post:repost']['logContext'],
|
logContext: Metrics['post:repost']['logContext'],
|
||||||
post: Shadow<AppBskyFeedDefs.PostView>,
|
post: Shadow<AppBskyFeedDefs.PostView>,
|
||||||
) {
|
) {
|
||||||
const agent = useAgent()
|
const pdsClient = usePdsClient()
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
return useMutation<
|
return useMutation<
|
||||||
{uri: string}, // responds with the uri of the repost
|
{uri: string}, // responds with the uri of the repost
|
||||||
@@ -323,7 +335,11 @@ function usePostRepostMutation(
|
|||||||
logContext,
|
logContext,
|
||||||
feedDescriptor,
|
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'],
|
logContext: Metrics['post:unrepost']['logContext'],
|
||||||
post: Shadow<AppBskyFeedDefs.PostView>,
|
post: Shadow<AppBskyFeedDefs.PostView>,
|
||||||
) {
|
) {
|
||||||
const agent = useAgent()
|
const pdsClient = usePdsClient()
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
return useMutation<void, Error, {postUri: string; repostUri: string}>({
|
return useMutation<void, Error, {postUri: string; repostUri: string}>({
|
||||||
mutationFn: ({postUri, repostUri}) => {
|
mutationFn: ({postUri, repostUri}) => {
|
||||||
@@ -343,17 +359,17 @@ function usePostUnrepostMutation(
|
|||||||
logContext,
|
logContext,
|
||||||
feedDescriptor,
|
feedDescriptor,
|
||||||
})
|
})
|
||||||
return agent.deleteRepost(repostUri)
|
return pdsClient.call(deleteRepost, repostUri as AtUriString)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function usePostDeleteMutation() {
|
export function usePostDeleteMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const pdsClient = usePdsClient()
|
||||||
return useMutation<void, Error, {uri: string}>({
|
return useMutation<void, Error, {uri: string}>({
|
||||||
mutationFn: async ({uri}) => {
|
mutationFn: async ({uri}) => {
|
||||||
await agent.deletePost(uri)
|
await pdsClient.call(deletePost, uri as AtUriString)
|
||||||
},
|
},
|
||||||
onSuccess(_, variables) {
|
onSuccess(_, variables) {
|
||||||
updatePostShadow(queryClient, variables.uri, {isDeleted: true})
|
updatePostShadow(queryClient, variables.uri, {isDeleted: true})
|
||||||
@@ -407,23 +423,29 @@ export function useThreadMuteMutationQueue(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function useThreadMuteMutation() {
|
function useThreadMuteMutation() {
|
||||||
const agent = useAgent()
|
const appviewClient = useAppviewClient()
|
||||||
return useMutation<
|
return useMutation<
|
||||||
{},
|
{},
|
||||||
Error,
|
Error,
|
||||||
{uri: string} // the root post's uri
|
{uri: string} // the root post's uri
|
||||||
>({
|
>({
|
||||||
mutationFn: ({uri}) => {
|
mutationFn: async ({uri}) => {
|
||||||
return agent.api.app.bsky.graph.muteThread({root: uri})
|
await appviewClient.call(app.bsky.graph.muteThread, {
|
||||||
|
root: uri as AtUriString,
|
||||||
|
})
|
||||||
|
return {}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function useThreadUnmuteMutation() {
|
function useThreadUnmuteMutation() {
|
||||||
const agent = useAgent()
|
const appviewClient = useAppviewClient()
|
||||||
return useMutation<{}, Error, {uri: string}>({
|
return useMutation<{}, Error, {uri: string}>({
|
||||||
mutationFn: ({uri}) => {
|
mutationFn: async ({uri}) => {
|
||||||
return agent.api.app.bsky.graph.unmuteThread({root: uri})
|
await appviewClient.call(app.bsky.graph.unmuteThread, {
|
||||||
|
root: uri as AtUriString,
|
||||||
|
})
|
||||||
|
return {}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,28 @@
|
|||||||
import {useCallback} from 'react'
|
import {useCallback} from 'react'
|
||||||
|
import {type AppBskyActorDefs} from '@atproto/api'
|
||||||
|
import {type DidString} from '@atproto/syntax'
|
||||||
import {
|
import {
|
||||||
type AppBskyActorDefs,
|
addSavedFeeds,
|
||||||
type BskyFeedViewPreference,
|
type BskyFeedViewPreference,
|
||||||
type LabelPreference,
|
dismissNudges,
|
||||||
} from '@atproto/api'
|
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 {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {PROD_DEFAULT_FEED} from '#/lib/constants'
|
import {PROD_DEFAULT_FEED} from '#/lib/constants'
|
||||||
@@ -20,11 +39,12 @@ import {
|
|||||||
type UsePreferencesQueryResponse,
|
type UsePreferencesQueryResponse,
|
||||||
} from '#/state/queries/preferences/types'
|
} from '#/state/queries/preferences/types'
|
||||||
import {createQueryKey} from '#/state/queries/util'
|
import {createQueryKey} from '#/state/queries/util'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAgent, usePdsClient} from '#/state/session'
|
||||||
import {saveLabelers} from '#/state/session/moderation'
|
import {saveLabelers} from '#/state/session/moderation'
|
||||||
import {useAgeAssurance} from '#/ageAssurance'
|
import {useAgeAssurance} from '#/ageAssurance'
|
||||||
import {makeAgeRestrictedModerationPrefs} from '#/ageAssurance/util'
|
import {makeAgeRestrictedModerationPrefs} from '#/ageAssurance/util'
|
||||||
import {useAnalytics} from '#/analytics'
|
import {useAnalytics} from '#/analytics'
|
||||||
|
import {app} from '#/lexicons'
|
||||||
|
|
||||||
export * from '#/state/queries/preferences/const'
|
export * from '#/state/queries/preferences/const'
|
||||||
export * from '#/state/queries/preferences/moderation'
|
export * from '#/state/queries/preferences/moderation'
|
||||||
@@ -37,6 +57,7 @@ export const preferencesQueryKey = createQueryKey(
|
|||||||
)
|
)
|
||||||
|
|
||||||
export function usePreferencesQuery() {
|
export function usePreferencesQuery() {
|
||||||
|
const client = usePdsClient()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const aa = useAgeAssurance()
|
const aa = useAgeAssurance()
|
||||||
|
|
||||||
@@ -47,18 +68,34 @@ export function usePreferencesQuery() {
|
|||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
gcTime: GCTIME.INFINITY,
|
gcTime: GCTIME.INFINITY,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
if (!agent.did) {
|
if (!client.did) {
|
||||||
return DEFAULT_LOGGED_OUT_PREFERENCES
|
return DEFAULT_LOGGED_OUT_PREFERENCES
|
||||||
} else {
|
} 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
|
// save to local storage to ensure there are labels on initial requests
|
||||||
saveLabelers(
|
saveLabelers(client.did, labelerDids)
|
||||||
agent.did,
|
|
||||||
res.moderationPrefs.labelers.map(l => l.did),
|
|
||||||
)
|
|
||||||
|
|
||||||
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,
|
...res,
|
||||||
savedFeeds: res.savedFeeds.filter(f => f.type !== 'unknown'),
|
savedFeeds: res.savedFeeds.filter(f => f.type !== 'unknown'),
|
||||||
/**
|
/**
|
||||||
@@ -74,7 +111,7 @@ export function usePreferencesQuery() {
|
|||||||
...(res.threadViewPrefs ?? {}),
|
...(res.threadViewPrefs ?? {}),
|
||||||
},
|
},
|
||||||
userAge: res.birthDate ? getAge(res.birthDate) : undefined,
|
userAge: res.birthDate ? getAge(res.birthDate) : undefined,
|
||||||
}
|
} as UsePreferencesQueryResponse
|
||||||
return preferences
|
return preferences
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -113,11 +150,11 @@ export function usePreferencesQuery() {
|
|||||||
|
|
||||||
export function useClearPreferencesMutation() {
|
export function useClearPreferencesMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
await agent.app.bsky.actor.putPreferences({preferences: []})
|
await client.call(app.bsky.actor.putPreferences, {preferences: []})
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
@@ -128,7 +165,7 @@ export function useClearPreferencesMutation() {
|
|||||||
|
|
||||||
export function usePreferencesSetContentLabelMutation() {
|
export function usePreferencesSetContentLabelMutation() {
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
return useMutation<
|
return useMutation<
|
||||||
@@ -137,7 +174,11 @@ export function usePreferencesSetContentLabelMutation() {
|
|||||||
{label: string; visibility: LabelPreference; labelerDid: string | undefined}
|
{label: string; visibility: LabelPreference; labelerDid: string | undefined}
|
||||||
>({
|
>({
|
||||||
mutationFn: async ({label, visibility, labelerDid}) => {
|
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})
|
ax.metric('moderation:changeLabelPreference', {preference: visibility})
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
@@ -149,7 +190,7 @@ export function usePreferencesSetContentLabelMutation() {
|
|||||||
|
|
||||||
export function useSetContentLabelMutation() {
|
export function useSetContentLabelMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async ({
|
mutationFn: async ({
|
||||||
@@ -161,7 +202,11 @@ export function useSetContentLabelMutation() {
|
|||||||
visibility: LabelPreference
|
visibility: LabelPreference
|
||||||
labelerDid?: string
|
labelerDid?: string
|
||||||
}) => {
|
}) => {
|
||||||
await agent.setContentLabelPref(label, visibility, labelerDid)
|
await client.call(setContentLabelPref, {
|
||||||
|
key: label,
|
||||||
|
value: visibility,
|
||||||
|
labelerDid: labelerDid as DidString | undefined,
|
||||||
|
})
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
@@ -172,11 +217,11 @@ export function useSetContentLabelMutation() {
|
|||||||
|
|
||||||
export function usePreferencesSetAdultContentMutation() {
|
export function usePreferencesSetAdultContentMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation<void, unknown, {enabled: boolean}>({
|
return useMutation<void, unknown, {enabled: boolean}>({
|
||||||
mutationFn: async ({enabled}) => {
|
mutationFn: async ({enabled}) => {
|
||||||
await agent.setAdultContentEnabled(enabled)
|
await client.call(setAdultContentEnabled, enabled)
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
@@ -187,7 +232,7 @@ export function usePreferencesSetAdultContentMutation() {
|
|||||||
|
|
||||||
export function useSetFeedViewPreferencesMutation() {
|
export function useSetFeedViewPreferencesMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation<void, unknown, Partial<BskyFeedViewPreference>>({
|
return useMutation<void, unknown, Partial<BskyFeedViewPreference>>({
|
||||||
mutationFn: async prefs => {
|
mutationFn: async prefs => {
|
||||||
@@ -195,7 +240,7 @@ export function useSetFeedViewPreferencesMutation() {
|
|||||||
* special handling here, merged into `feedViewPrefs` above, since
|
* special handling here, merged into `feedViewPrefs` above, since
|
||||||
* following was previously called `home`
|
* following was previously called `home`
|
||||||
*/
|
*/
|
||||||
await agent.setFeedViewPrefs('home', prefs)
|
await client.call(setFeedViewPrefs, {feed: 'home', ...prefs})
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
@@ -212,11 +257,11 @@ export function useSetThreadViewPreferencesMutation({
|
|||||||
onError?: (error: unknown) => void
|
onError?: (error: unknown) => void
|
||||||
}) {
|
}) {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation<void, unknown, Partial<ThreadViewPreferences>>({
|
return useMutation<void, unknown, Partial<ThreadViewPreferences>>({
|
||||||
mutationFn: async prefs => {
|
mutationFn: async prefs => {
|
||||||
await agent.setThreadViewPrefs(prefs)
|
await client.call(setThreadViewPrefs, prefs)
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
@@ -229,11 +274,11 @@ export function useSetThreadViewPreferencesMutation({
|
|||||||
|
|
||||||
export function useOverwriteSavedFeedsMutation() {
|
export function useOverwriteSavedFeedsMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation<void, unknown, AppBskyActorDefs.SavedFeed[]>({
|
return useMutation<void, unknown, AppBskyActorDefs.SavedFeed[]>({
|
||||||
mutationFn: async savedFeeds => {
|
mutationFn: async savedFeeds => {
|
||||||
await agent.overwriteSavedFeeds(savedFeeds)
|
await client.call(overwriteSavedFeeds, savedFeeds)
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
@@ -244,7 +289,7 @@ export function useOverwriteSavedFeedsMutation() {
|
|||||||
|
|
||||||
export function useAddSavedFeedsMutation() {
|
export function useAddSavedFeedsMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation<
|
return useMutation<
|
||||||
void,
|
void,
|
||||||
@@ -252,7 +297,7 @@ export function useAddSavedFeedsMutation() {
|
|||||||
Pick<AppBskyActorDefs.SavedFeed, 'type' | 'value' | 'pinned'>[]
|
Pick<AppBskyActorDefs.SavedFeed, 'type' | 'value' | 'pinned'>[]
|
||||||
>({
|
>({
|
||||||
mutationFn: async savedFeeds => {
|
mutationFn: async savedFeeds => {
|
||||||
await agent.addSavedFeeds(savedFeeds)
|
await client.call(addSavedFeeds, savedFeeds)
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
@@ -263,11 +308,11 @@ export function useAddSavedFeedsMutation() {
|
|||||||
|
|
||||||
export function useRemoveFeedMutation() {
|
export function useRemoveFeedMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation<void, unknown, Pick<AppBskyActorDefs.SavedFeed, 'id'>>({
|
return useMutation<void, unknown, Pick<AppBskyActorDefs.SavedFeed, 'id'>>({
|
||||||
mutationFn: async savedFeed => {
|
mutationFn: async savedFeed => {
|
||||||
await agent.removeSavedFeeds([savedFeed.id])
|
await client.call(removeSavedFeeds, [savedFeed.id])
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
@@ -278,7 +323,7 @@ export function useRemoveFeedMutation() {
|
|||||||
|
|
||||||
export function useReplaceForYouWithDiscoverFeedMutation() {
|
export function useReplaceForYouWithDiscoverFeedMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async ({
|
mutationFn: async ({
|
||||||
@@ -289,10 +334,10 @@ export function useReplaceForYouWithDiscoverFeedMutation() {
|
|||||||
discoverFeedConfig: AppBskyActorDefs.SavedFeed | undefined
|
discoverFeedConfig: AppBskyActorDefs.SavedFeed | undefined
|
||||||
}) => {
|
}) => {
|
||||||
if (forYouFeedConfig) {
|
if (forYouFeedConfig) {
|
||||||
await agent.removeSavedFeeds([forYouFeedConfig.id])
|
await client.call(removeSavedFeeds, [forYouFeedConfig.id])
|
||||||
}
|
}
|
||||||
if (!discoverFeedConfig) {
|
if (!discoverFeedConfig) {
|
||||||
await agent.addSavedFeeds([
|
await client.call(addSavedFeeds, [
|
||||||
{
|
{
|
||||||
type: 'feed',
|
type: 'feed',
|
||||||
value: PROD_DEFAULT_FEED('whats-hot'),
|
value: PROD_DEFAULT_FEED('whats-hot'),
|
||||||
@@ -300,7 +345,7 @@ export function useReplaceForYouWithDiscoverFeedMutation() {
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
} else {
|
} else {
|
||||||
await agent.updateSavedFeeds([
|
await client.call(updateSavedFeeds, [
|
||||||
{
|
{
|
||||||
...discoverFeedConfig,
|
...discoverFeedConfig,
|
||||||
pinned: true,
|
pinned: true,
|
||||||
@@ -317,11 +362,11 @@ export function useReplaceForYouWithDiscoverFeedMutation() {
|
|||||||
|
|
||||||
export function useUpdateSavedFeedsMutation() {
|
export function useUpdateSavedFeedsMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation<void, unknown, AppBskyActorDefs.SavedFeed[]>({
|
return useMutation<void, unknown, AppBskyActorDefs.SavedFeed[]>({
|
||||||
mutationFn: async feeds => {
|
mutationFn: async feeds => {
|
||||||
await agent.updateSavedFeeds(feeds)
|
await client.call(updateSavedFeeds, feeds)
|
||||||
|
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
@@ -333,11 +378,14 @@ export function useUpdateSavedFeedsMutation() {
|
|||||||
|
|
||||||
export function useUpsertMutedWordsMutation() {
|
export function useUpsertMutedWordsMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async (mutedWords: AppBskyActorDefs.MutedWord[]) => {
|
mutationFn: async (mutedWords: AppBskyActorDefs.MutedWord[]) => {
|
||||||
await agent.upsertMutedWords(mutedWords)
|
await client.call(
|
||||||
|
upsertMutedWords,
|
||||||
|
mutedWords as app.bsky.actor.defs.MutedWord[],
|
||||||
|
)
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
@@ -348,11 +396,14 @@ export function useUpsertMutedWordsMutation() {
|
|||||||
|
|
||||||
export function useUpdateMutedWordMutation() {
|
export function useUpdateMutedWordMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async (mutedWord: AppBskyActorDefs.MutedWord) => {
|
mutationFn: async (mutedWord: AppBskyActorDefs.MutedWord) => {
|
||||||
await agent.updateMutedWord(mutedWord)
|
await client.call(
|
||||||
|
updateMutedWord,
|
||||||
|
mutedWord as app.bsky.actor.defs.MutedWord,
|
||||||
|
)
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
@@ -363,11 +414,14 @@ export function useUpdateMutedWordMutation() {
|
|||||||
|
|
||||||
export function useRemoveMutedWordMutation() {
|
export function useRemoveMutedWordMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async (mutedWord: AppBskyActorDefs.MutedWord) => {
|
mutationFn: async (mutedWord: AppBskyActorDefs.MutedWord) => {
|
||||||
await agent.removeMutedWord(mutedWord)
|
await client.call(
|
||||||
|
removeMutedWord,
|
||||||
|
mutedWord as app.bsky.actor.defs.MutedWord,
|
||||||
|
)
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
@@ -378,11 +432,14 @@ export function useRemoveMutedWordMutation() {
|
|||||||
|
|
||||||
export function useRemoveMutedWordsMutation() {
|
export function useRemoveMutedWordsMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async (mutedWords: AppBskyActorDefs.MutedWord[]) => {
|
mutationFn: async (mutedWords: AppBskyActorDefs.MutedWord[]) => {
|
||||||
await agent.removeMutedWords(mutedWords)
|
await client.call(
|
||||||
|
removeMutedWords,
|
||||||
|
mutedWords as app.bsky.actor.defs.MutedWord[],
|
||||||
|
)
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
@@ -393,11 +450,11 @@ export function useRemoveMutedWordsMutation() {
|
|||||||
|
|
||||||
export function useQueueNudgesMutation() {
|
export function useQueueNudgesMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async (nudges: string | string[]) => {
|
mutationFn: async (nudges: string | string[]) => {
|
||||||
await agent.bskyAppQueueNudges(nudges)
|
await client.call(queueNudges, Array.isArray(nudges) ? nudges : [nudges])
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
@@ -408,11 +465,14 @@ export function useQueueNudgesMutation() {
|
|||||||
|
|
||||||
export function useDismissNudgesMutation() {
|
export function useDismissNudgesMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async (nudges: string | string[]) => {
|
mutationFn: async (nudges: string | string[]) => {
|
||||||
await agent.bskyAppDismissNudges(nudges)
|
await client.call(
|
||||||
|
dismissNudges,
|
||||||
|
Array.isArray(nudges) ? nudges : [nudges],
|
||||||
|
)
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
@@ -423,13 +483,13 @@ export function useDismissNudgesMutation() {
|
|||||||
|
|
||||||
export function useSetActiveProgressGuideMutation() {
|
export function useSetActiveProgressGuideMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async (
|
mutationFn: async (
|
||||||
guide: AppBskyActorDefs.BskyAppProgressGuide | undefined,
|
guide: AppBskyActorDefs.BskyAppProgressGuide | undefined,
|
||||||
) => {
|
) => {
|
||||||
await agent.bskyAppSetActiveProgressGuide(guide)
|
await client.call(setActiveProgressGuide, guide)
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
@@ -440,11 +500,11 @@ export function useSetActiveProgressGuideMutation() {
|
|||||||
|
|
||||||
export function useSetIsBetaUserMutation() {
|
export function useSetIsBetaUserMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async (isBetaUser: boolean) => {
|
mutationFn: async (isBetaUser: boolean) => {
|
||||||
await agent.setIsBetaUser(isBetaUser)
|
await client.call(setIsBetaUser, isBetaUser)
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
@@ -456,11 +516,11 @@ export function useSetIsBetaUserMutation() {
|
|||||||
export function useSetVerificationPrefsMutation() {
|
export function useSetVerificationPrefsMutation() {
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const client = usePdsClient()
|
||||||
|
|
||||||
return useMutation<void, unknown, AppBskyActorDefs.VerificationPrefs>({
|
return useMutation<void, unknown, AppBskyActorDefs.VerificationPrefs>({
|
||||||
mutationFn: async prefs => {
|
mutationFn: async prefs => {
|
||||||
await agent.setVerificationPrefs(prefs)
|
await client.call(setVerificationPrefs, prefs)
|
||||||
if (prefs.hideBadges) {
|
if (prefs.hideBadges) {
|
||||||
ax.metric('verification:settings:hideBadges', {})
|
ax.metric('verification:settings:hideBadges', {})
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -3,17 +3,24 @@ import {
|
|||||||
type AppBskyActorDefs,
|
type AppBskyActorDefs,
|
||||||
type AppBskyActorGetProfile,
|
type AppBskyActorGetProfile,
|
||||||
type AppBskyActorGetProfiles,
|
type AppBskyActorGetProfiles,
|
||||||
type AppBskyActorProfile,
|
|
||||||
type AppBskyGraphGetFollows,
|
type AppBskyGraphGetFollows,
|
||||||
type AtpAgent,
|
|
||||||
AtUri,
|
AtUri,
|
||||||
type Un$Typed,
|
type Un$Typed,
|
||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
|
import {type Client} from '@atproto/lex'
|
||||||
import {
|
import {
|
||||||
type AtIdentifierString,
|
type AtIdentifierString,
|
||||||
|
type AtUriString,
|
||||||
type DidString,
|
type DidString,
|
||||||
toDatetimeString,
|
toDatetimeString,
|
||||||
} from '@atproto/syntax'
|
} from '@atproto/syntax'
|
||||||
|
import {
|
||||||
|
deleteFollow,
|
||||||
|
follow,
|
||||||
|
muteActor,
|
||||||
|
unmuteActor,
|
||||||
|
upsertProfile,
|
||||||
|
} from '@bsky.app/sdk'
|
||||||
import {
|
import {
|
||||||
type InfiniteData,
|
type InfiniteData,
|
||||||
keepPreviousData,
|
keepPreviousData,
|
||||||
@@ -24,7 +31,6 @@ import {
|
|||||||
} from '@tanstack/react-query'
|
} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {uploadBlob} from '#/lib/api'
|
import {uploadBlob} from '#/lib/api'
|
||||||
import {toLegacyBlobRef} from '#/lib/api/legacy-blob'
|
|
||||||
import {until} from '#/lib/async/until'
|
import {until} from '#/lib/async/until'
|
||||||
import {useToggleMutationQueue} from '#/lib/hooks/useToggleMutationQueue'
|
import {useToggleMutationQueue} from '#/lib/hooks/useToggleMutationQueue'
|
||||||
import {updateProfileShadow} from '#/state/cache/profile-shadow'
|
import {updateProfileShadow} from '#/state/cache/profile-shadow'
|
||||||
@@ -38,7 +44,7 @@ import {
|
|||||||
useUnstableProfileViewCache,
|
useUnstableProfileViewCache,
|
||||||
} from '#/state/queries/unstable-profile-cache'
|
} from '#/state/queries/unstable-profile-cache'
|
||||||
import {useUpdateProfileVerificationCache} from '#/state/queries/verification/useUpdateProfileVerificationCache'
|
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 * as userActionHistory from '#/state/userActionHistory'
|
||||||
import {useAnalytics} from '#/analytics'
|
import {useAnalytics} from '#/analytics'
|
||||||
import {type Metrics, toClout} from '#/analytics/metrics'
|
import {type Metrics, toClout} from '#/analytics/metrics'
|
||||||
@@ -74,7 +80,7 @@ export function useProfileQuery({
|
|||||||
did: string | undefined
|
did: string | undefined
|
||||||
staleTime?: number
|
staleTime?: number
|
||||||
}) {
|
}) {
|
||||||
const agent = useAgent()
|
const client = useAppviewClient()
|
||||||
const {getUnstableProfile} = useUnstableProfileViewCache()
|
const {getUnstableProfile} = useUnstableProfileViewCache()
|
||||||
return useQuery<AppBskyActorDefs.ProfileViewDetailed>({
|
return useQuery<AppBskyActorDefs.ProfileViewDetailed>({
|
||||||
// WARNING
|
// WARNING
|
||||||
@@ -85,8 +91,9 @@ export function useProfileQuery({
|
|||||||
refetchOnWindowFocus: true,
|
refetchOnWindowFocus: true,
|
||||||
queryKey: RQKEY(did ?? ''),
|
queryKey: RQKEY(did ?? ''),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const res = await agent.getProfile({actor: did ?? ''})
|
return await client.call(app.bsky.actor.getProfile, {
|
||||||
return res.data
|
actor: (did ?? '') as AtIdentifierString,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
placeholderData: () => {
|
placeholderData: () => {
|
||||||
if (!did) return
|
if (!did) return
|
||||||
@@ -103,21 +110,22 @@ export function useProfilesQuery({
|
|||||||
handles: string[]
|
handles: string[]
|
||||||
maintainData?: boolean
|
maintainData?: boolean
|
||||||
}) {
|
}) {
|
||||||
const agent = useAgent()
|
const client = useAppviewClient()
|
||||||
return useQuery({
|
return useQuery({
|
||||||
enabled: handles.length > 0,
|
enabled: handles.length > 0,
|
||||||
staleTime: STALE.MINUTES.FIVE,
|
staleTime: STALE.MINUTES.FIVE,
|
||||||
queryKey: profilesQueryKey(handles),
|
queryKey: profilesQueryKey(handles),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const res = await agent.getProfiles({actors: handles})
|
return await client.call(app.bsky.actor.getProfiles, {
|
||||||
return res.data
|
actors: handles as AtIdentifierString[],
|
||||||
|
})
|
||||||
},
|
},
|
||||||
placeholderData: maintainData ? keepPreviousData : undefined,
|
placeholderData: maintainData ? keepPreviousData : undefined,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function usePrefetchProfileQuery() {
|
export function usePrefetchProfileQuery() {
|
||||||
const agent = useAgent()
|
const client = useAppviewClient()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const prefetchProfileQuery = useCallback(
|
const prefetchProfileQuery = useCallback(
|
||||||
async (did: string) => {
|
async (did: string) => {
|
||||||
@@ -125,12 +133,13 @@ export function usePrefetchProfileQuery() {
|
|||||||
staleTime: STALE.SECONDS.THIRTY,
|
staleTime: STALE.SECONDS.THIRTY,
|
||||||
queryKey: RQKEY(did),
|
queryKey: RQKEY(did),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const res = await agent.getProfile({actor: did || ''})
|
return await client.call(app.bsky.actor.getProfile, {
|
||||||
return res.data
|
actor: (did || '') as AtIdentifierString,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
[queryClient, agent],
|
[queryClient, client],
|
||||||
)
|
)
|
||||||
return prefetchProfileQuery
|
return prefetchProfileQuery
|
||||||
}
|
}
|
||||||
@@ -138,18 +147,18 @@ export function usePrefetchProfileQuery() {
|
|||||||
interface ProfileUpdateParams {
|
interface ProfileUpdateParams {
|
||||||
profile: AppBskyActorDefs.ProfileViewDetailed
|
profile: AppBskyActorDefs.ProfileViewDetailed
|
||||||
updates:
|
updates:
|
||||||
| Un$Typed<AppBskyActorProfile.Record>
|
| Un$Typed<app.bsky.actor.profile.Main>
|
||||||
| ((
|
| ((
|
||||||
existing: Un$Typed<AppBskyActorProfile.Record>,
|
existing: Un$Typed<app.bsky.actor.profile.Main>,
|
||||||
) => Un$Typed<AppBskyActorProfile.Record>)
|
) => Un$Typed<app.bsky.actor.profile.Main>)
|
||||||
newUserAvatar?: ImageMeta | undefined | null
|
newUserAvatar?: ImageMeta | undefined | null
|
||||||
newUserBanner?: ImageMeta | undefined | null
|
newUserBanner?: ImageMeta | undefined | null
|
||||||
checkCommitted?: (res: AppBskyActorGetProfile.Response) => boolean
|
checkCommitted?: (res: AppBskyActorGetProfile.Response) => boolean
|
||||||
}
|
}
|
||||||
export function useProfileUpdateMutation() {
|
export function useProfileUpdateMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
|
||||||
const pdsClient = usePdsClient()
|
const pdsClient = usePdsClient()
|
||||||
|
const appviewClient = useAppviewClient()
|
||||||
const updateProfileVerificationCache = useUpdateProfileVerificationCache()
|
const updateProfileVerificationCache = useUpdateProfileVerificationCache()
|
||||||
return useMutation<void, Error, ProfileUpdateParams>({
|
return useMutation<void, Error, ProfileUpdateParams>({
|
||||||
mutationFn: async ({
|
mutationFn: async ({
|
||||||
@@ -175,8 +184,8 @@ export function useProfileUpdateMutation() {
|
|||||||
newUserBanner.mime,
|
newUserBanner.mime,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
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 (typeof updates === 'function') {
|
if (typeof updates === 'function') {
|
||||||
next = updates(next)
|
next = updates(next)
|
||||||
} else {
|
} else {
|
||||||
@@ -188,20 +197,20 @@ export function useProfileUpdateMutation() {
|
|||||||
}
|
}
|
||||||
if (newUserAvatarPromise) {
|
if (newUserAvatarPromise) {
|
||||||
const res = await newUserAvatarPromise
|
const res = await newUserAvatarPromise
|
||||||
next.avatar = toLegacyBlobRef(res.blob)
|
next.avatar = res.blob
|
||||||
} else if (newUserAvatar === null) {
|
} else if (newUserAvatar === null) {
|
||||||
next.avatar = undefined
|
next.avatar = undefined
|
||||||
}
|
}
|
||||||
if (newUserBannerPromise) {
|
if (newUserBannerPromise) {
|
||||||
const res = await newUserBannerPromise
|
const res = await newUserBannerPromise
|
||||||
next.banner = toLegacyBlobRef(res.blob)
|
next.banner = res.blob
|
||||||
} else if (newUserBanner === null) {
|
} else if (newUserBanner === null) {
|
||||||
next.banner = undefined
|
next.banner = undefined
|
||||||
}
|
}
|
||||||
return next
|
return next
|
||||||
})
|
})
|
||||||
await whenAppViewReady(
|
await whenAppViewReady(
|
||||||
agent,
|
appviewClient,
|
||||||
profile.did,
|
profile.did,
|
||||||
checkCommitted ||
|
checkCommitted ||
|
||||||
(res => {
|
(res => {
|
||||||
@@ -252,7 +261,7 @@ export function useProfileFollowMutationQueue(
|
|||||||
position?: number,
|
position?: number,
|
||||||
contextProfileDid?: string,
|
contextProfileDid?: string,
|
||||||
) {
|
) {
|
||||||
const agent = useAgent()
|
const client = useAppviewClient()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const did = profile.did
|
const did = profile.did
|
||||||
@@ -333,12 +342,12 @@ export function useProfileFollowMutationQueue(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (finalFollowingUri) {
|
if (finalFollowingUri) {
|
||||||
void agent.app.bsky.graph
|
void client
|
||||||
.getSuggestedFollowsByActor({
|
.call(app.bsky.graph.getSuggestedFollowsByActor, {
|
||||||
actor: did,
|
actor: did as AtIdentifierString,
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
const dids = res.data.suggestions
|
const dids = res.suggestions
|
||||||
.filter(a => !a.viewer?.following)
|
.filter(a => !a.viewer?.following)
|
||||||
.map(a => a.did)
|
.map(a => a.did)
|
||||||
.slice(0, 8)
|
.slice(0, 8)
|
||||||
@@ -375,7 +384,7 @@ function useProfileFollowMutation(
|
|||||||
) {
|
) {
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const agent = useAgent()
|
const pdsClient = usePdsClient()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const {captureAction} = useProgressGuideControls()
|
const {captureAction} = useProgressGuideControls()
|
||||||
|
|
||||||
@@ -400,7 +409,7 @@ function useProfileFollowMutation(
|
|||||||
position,
|
position,
|
||||||
contextProfileDid,
|
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'],
|
logContext: Metrics['profile:unfollow']['logContext'],
|
||||||
) {
|
) {
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
const agent = useAgent()
|
const pdsClient = usePdsClient()
|
||||||
return useMutation<void, Error, {did: string; followUri: string}>({
|
return useMutation<void, Error, {did: string; followUri: string}>({
|
||||||
mutationFn: async ({followUri}) => {
|
mutationFn: async ({followUri}) => {
|
||||||
ax.metric('profile:unfollow', {logContext})
|
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 ax = useAnalytics()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const did = profile.did
|
const did = profile.did as DidString
|
||||||
const initialMuted = profile.viewer?.muted
|
const initialMuted = profile.viewer?.muted
|
||||||
const muteMutation = useProfileMuteMutation()
|
const muteMutation = useProfileMuteMutation()
|
||||||
const unmuteMutation = useProfileUnmuteMutation()
|
const unmuteMutation = useProfileUnmuteMutation()
|
||||||
@@ -432,15 +441,11 @@ export function useProfileMuteMutationQueue(
|
|||||||
initialState: initialMuted,
|
initialState: initialMuted,
|
||||||
runMutation: async (_prevMuted, shouldMute) => {
|
runMutation: async (_prevMuted, shouldMute) => {
|
||||||
if (shouldMute) {
|
if (shouldMute) {
|
||||||
await muteMutation.mutateAsync({
|
await muteMutation.mutateAsync({did})
|
||||||
did,
|
|
||||||
})
|
|
||||||
ax.metric('profile:mute', {})
|
ax.metric('profile:mute', {})
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
await unmuteMutation.mutateAsync({
|
await unmuteMutation.mutateAsync({did})
|
||||||
did,
|
|
||||||
})
|
|
||||||
ax.metric('profile:unmute', {})
|
ax.metric('profile:unmute', {})
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -485,7 +490,7 @@ export function useProfileMuteRepostsMutationQueue(
|
|||||||
) {
|
) {
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const did = profile.did
|
const did = profile.did as DidString
|
||||||
const initialMutedOnlyReposts = !!profile.viewer?.mutedOnlyReposts
|
const initialMutedOnlyReposts = !!profile.viewer?.mutedOnlyReposts
|
||||||
const muteRepostsMutation = useProfileMuteRepostsMutation()
|
const muteRepostsMutation = useProfileMuteRepostsMutation()
|
||||||
const unmuteMutation = useProfileUnmuteMutation()
|
const unmuteMutation = useProfileUnmuteMutation()
|
||||||
@@ -494,15 +499,11 @@ export function useProfileMuteRepostsMutationQueue(
|
|||||||
initialState: initialMutedOnlyReposts,
|
initialState: initialMutedOnlyReposts,
|
||||||
runMutation: async (_prevMutedOnlyReposts, shouldMute) => {
|
runMutation: async (_prevMutedOnlyReposts, shouldMute) => {
|
||||||
if (shouldMute) {
|
if (shouldMute) {
|
||||||
await muteRepostsMutation.mutateAsync({
|
await muteRepostsMutation.mutateAsync({did})
|
||||||
did,
|
|
||||||
})
|
|
||||||
ax.metric('profile:muteReposts', {})
|
ax.metric('profile:muteReposts', {})
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
await unmuteMutation.mutateAsync({
|
await unmuteMutation.mutateAsync({did})
|
||||||
did,
|
|
||||||
})
|
|
||||||
ax.metric('profile:unmuteReposts', {})
|
ax.metric('profile:unmuteReposts', {})
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -536,10 +537,10 @@ export function useProfileMuteRepostsMutationQueue(
|
|||||||
|
|
||||||
function useProfileMuteMutation() {
|
function useProfileMuteMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const appviewClient = useAppviewClient()
|
||||||
return useMutation<void, Error, {did: string}>({
|
return useMutation({
|
||||||
mutationFn: async ({did}) => {
|
mutationFn: async ({did}: {did: DidString}) => {
|
||||||
await agent.mute(did)
|
await appviewClient.call(muteActor, {actor: did})
|
||||||
},
|
},
|
||||||
onSuccess() {
|
onSuccess() {
|
||||||
void queryClient.invalidateQueries({queryKey: RQKEY_MY_MUTED()})
|
void queryClient.invalidateQueries({queryKey: RQKEY_MY_MUTED()})
|
||||||
@@ -549,10 +550,14 @@ function useProfileMuteMutation() {
|
|||||||
|
|
||||||
function useProfileMuteRepostsMutation() {
|
function useProfileMuteRepostsMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const appviewClient = useAppviewClient()
|
||||||
return useMutation<void, Error, {did: string}>({
|
return useMutation({
|
||||||
mutationFn: async ({did}) => {
|
mutationFn: async ({did}: {did: DidString}) => {
|
||||||
await agent.mute(did, {onlyReposts: true})
|
await appviewClient.call(muteActor, {
|
||||||
|
actor: did,
|
||||||
|
// @ts-expect-error missing from this SDK version, remove this
|
||||||
|
onlyReposts: true,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
onSuccess() {
|
onSuccess() {
|
||||||
void queryClient.invalidateQueries({queryKey: RQKEY_MY_MUTED()})
|
void queryClient.invalidateQueries({queryKey: RQKEY_MY_MUTED()})
|
||||||
@@ -562,10 +567,10 @@ function useProfileMuteRepostsMutation() {
|
|||||||
|
|
||||||
function useProfileUnmuteMutation() {
|
function useProfileUnmuteMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const appviewClient = useAppviewClient()
|
||||||
return useMutation<void, Error, {did: string}>({
|
return useMutation({
|
||||||
mutationFn: async ({did}) => {
|
mutationFn: async ({did}: {did: DidString}) => {
|
||||||
await agent.unmute(did)
|
await appviewClient.call(unmuteActor, {actor: did})
|
||||||
},
|
},
|
||||||
onSuccess() {
|
onSuccess() {
|
||||||
void queryClient.invalidateQueries({queryKey: RQKEY_MY_MUTED()})
|
void queryClient.invalidateQueries({queryKey: RQKEY_MY_MUTED()})
|
||||||
@@ -679,7 +684,7 @@ function useProfileUnblockMutation() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function whenAppViewReady(
|
async function whenAppViewReady(
|
||||||
agent: AtpAgent,
|
client: Client,
|
||||||
actor: string,
|
actor: string,
|
||||||
fn: (res: AppBskyActorGetProfile.Response) => boolean,
|
fn: (res: AppBskyActorGetProfile.Response) => boolean,
|
||||||
) {
|
) {
|
||||||
@@ -687,7 +692,17 @@ async function whenAppViewReady(
|
|||||||
5, // 5 tries
|
5, // 5 tries
|
||||||
1e3, // 1s delay between tries
|
1e3, // 1s delay between tries
|
||||||
fn,
|
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,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,8 +26,8 @@ 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 {agentToAppviewClient, agentToPdsClient} from './clients'
|
||||||
import {configureModerationForAccount} from './moderation'
|
import {configureModerationForAccount} from './moderation'
|
||||||
import {
|
import {
|
||||||
buildBundle,
|
buildBundle,
|
||||||
@@ -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()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -100,22 +105,23 @@ export async function createSessionBundleAndCreateAccount(
|
|||||||
setCreatedAtForDid({did: earlyAccount.did, createdAt})
|
setCreatedAtForDid({did: earlyAccount.did, createdAt})
|
||||||
setBirthdateForDid({did: earlyAccount.did, birthdate})
|
setBirthdateForDid({did: earlyAccount.did, birthdate})
|
||||||
snoozeBirthdateUpdateAllowedForDid(earlyAccount.did)
|
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.
|
// 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 isProd = Boolean(IS_PROD_SERVICE(service))
|
||||||
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 +176,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()},
|
||||||
]),
|
]),
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
createPublicAgent,
|
createPublicAgent,
|
||||||
PasswordSessionManager,
|
PasswordSessionManager,
|
||||||
} from './bridge-agent'
|
} from './bridge-agent'
|
||||||
|
import {agentToAppviewClient, agentToPdsClient} from './clients'
|
||||||
import {addSessionErrorLog} from './logging'
|
import {addSessionErrorLog} from './logging'
|
||||||
import {configureModerationForAccount} from './moderation'
|
import {configureModerationForAccount} from './moderation'
|
||||||
import {networkAwareFetch} from './network'
|
import {networkAwareFetch} from './network'
|
||||||
@@ -290,7 +291,10 @@ export async function createSessionBundleAndResume(
|
|||||||
) ?? storedAccount
|
) ?? storedAccount
|
||||||
|
|
||||||
configureModerationForAccount(bundle.agent, earlyAccount)
|
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
|
* 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'})
|
const gates = features.refresh({strategy: 'prefer-fresh-gates'})
|
||||||
configureModerationForAccount(bundle.agent, earlyAccount)
|
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())
|
bundle.agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user