Write chat declaration record in response to different events (#10216)

Co-authored-by: Eric Bailey <git@esb.lol>
This commit is contained in:
DS Boyce
2026-04-20 13:39:12 -07:00
committed by GitHub
parent d58ff89441
commit 8c2e4c6fad
10 changed files with 298 additions and 125 deletions
+31 -4
View File
@@ -4,6 +4,7 @@ import {
type AppBskyAgeassuranceGetConfig, type AppBskyAgeassuranceGetConfig,
type AppBskyAgeassuranceGetState, type AppBskyAgeassuranceGetState,
AtpAgent, AtpAgent,
type ChatBskyActorDeclaration,
getAgeAssuranceRegionConfig, getAgeAssuranceRegionConfig,
} from '@atproto/api' } from '@atproto/api'
import {createAsyncStoragePersister} from '@tanstack/query-async-storage-persister' import {createAsyncStoragePersister} from '@tanstack/query-async-storage-persister'
@@ -19,6 +20,7 @@ import {
hasSnoozedBirthdateUpdateForDid, hasSnoozedBirthdateUpdateForDid,
snoozeBirthdateUpdateAllowedForDid, snoozeBirthdateUpdateAllowedForDid,
} from '#/state/birthdate' } from '#/state/birthdate'
import {fetchActorDeclarationRecord} from '#/state/queries/messages/actor-declaration'
import {useAgent, useSession} from '#/state/session' import {useAgent, useSession} from '#/state/session'
import * as debug from '#/ageAssurance/debug' import * as debug from '#/ageAssurance/debug'
import {logger} from '#/ageAssurance/logger' import {logger} from '#/ageAssurance/logger'
@@ -53,7 +55,7 @@ const [, cacheHydrationPromise] = persistQueryClient({
persister, persister,
}) })
function getDidFromAgentSession(agent: AtpAgent) { export function getDidFromAgentSession(agent: AtpAgent) {
const sessionManager = agent.sessionManager const sessionManager = agent.sessionManager
if (!sessionManager || !sessionManager.did) return if (!sessionManager || !sessionManager.did) return
return sessionManager.did return sessionManager.did
@@ -329,19 +331,25 @@ export function useServerStateQuery() {
export type OtherRequiredData = { export type OtherRequiredData = {
birthdate: string | undefined birthdate: string | undefined
actorDeclaration?: ChatBskyActorDeclaration.Main
} }
export function createOtherRequiredDataQueryKey({did}: {did: string}) { export function createOtherRequiredDataQueryKey({did}: {did: string}) {
return ['otherRequiredData', did] return ['otherRequiredData', did]
} }
export async function getOtherRequiredData({ async function getOtherRequiredData({
agent, agent,
}: { }: {
agent: AtpAgent agent: AtpAgent
}): Promise<OtherRequiredData> { }): Promise<OtherRequiredData> {
if (debug.enabled) return debug.resolve(debug.otherRequiredData) if (debug.enabled) return debug.resolve(debug.otherRequiredData)
const [prefs] = await Promise.all([agent.getPreferences()]) const did = getDidFromAgentSession(agent)
const [prefs, actorDeclaration] = await Promise.all([
agent.getPreferences(),
fetchActorDeclarationRecord({did, agent}),
])
const data: OtherRequiredData = { const data: OtherRequiredData = {
birthdate: prefs.birthDate ? prefs.birthDate.toISOString() : undefined, birthdate: prefs.birthDate ? prefs.birthDate.toISOString() : undefined,
actorDeclaration,
} }
/** /**
@@ -359,7 +367,6 @@ export async function getOtherRequiredData({
} }
} }
const did = getDidFromAgentSession(agent)
if (data && did && birthdateCache.has(did)) { if (data && did && birthdateCache.has(did)) {
/* /*
* If birthdate was just set, use the local cache value. On subsequent * If birthdate was just set, use the local cache value. On subsequent
@@ -394,6 +401,26 @@ export function getOtherRequiredDataFromCache({
createOtherRequiredDataQueryKey({did}), createOtherRequiredDataQueryKey({did}),
) )
} }
export function setOtherRequiredDataActorDeclarationCache({
did,
actorDeclaration,
}: {
did: string
actorDeclaration: ChatBskyActorDeclaration.Main
}) {
const prev = getOtherRequiredDataFromCache({did})
const next: OtherRequiredData = {
birthdate: prev?.birthdate,
actorDeclaration: {
...(prev?.actorDeclaration || {}),
...actorDeclaration,
},
}
qc.setQueryData<OtherRequiredData>(
createOtherRequiredDataQueryKey({did}),
next,
)
}
export async function prefetchOtherRequiredData({agent}: {agent: AtpAgent}) { export async function prefetchOtherRequiredData({agent}: {agent: AtpAgent}) {
const did = getDidFromAgentSession(agent) const did = getDidFromAgentSession(agent)
+9 -4
View File
@@ -1,6 +1,7 @@
import {createContext, useCallback, useContext, useEffect, useMemo} from 'react' import {createContext, useCallback, useContext, useEffect, useMemo} from 'react'
import {useGetAndRegisterPushToken} from '#/lib/notifications/notifications' import {useGetAndRegisterPushToken} from '#/lib/notifications/notifications'
import {useAgent} from '#/state/session'
import {Provider as RedirectOverlayProvider} from '#/ageAssurance/components/RedirectOverlay' import {Provider as RedirectOverlayProvider} from '#/ageAssurance/components/RedirectOverlay'
import { import {
AgeAssuranceDataProvider, AgeAssuranceDataProvider,
@@ -18,6 +19,7 @@ import {
} from '#/ageAssurance/types' } from '#/ageAssurance/types'
import { import {
isUnderAge, isUnderAge,
maybeRestrictChatSettings,
MIN_ACCESS_AGE, MIN_ACCESS_AGE,
useAgeAssuranceRegionConfigWithFallback, useAgeAssuranceRegionConfigWithFallback,
} from '#/ageAssurance/util' } from '#/ageAssurance/util'
@@ -78,6 +80,7 @@ export function Provider({children}: {children: React.ReactNode}) {
} }
function InnerProvider({children}: {children: React.ReactNode}) { function InnerProvider({children}: {children: React.ReactNode}) {
const agent = useAgent()
const state = useAgeAssuranceState() const state = useAgeAssuranceState()
const {data} = useAgeAssuranceDataContext() const {data} = useAgeAssuranceDataContext()
const config = useAgeAssuranceRegionConfigWithFallback() const config = useAgeAssuranceRegionConfigWithFallback()
@@ -85,11 +88,13 @@ function InnerProvider({children}: {children: React.ReactNode}) {
const handleAccessUpdate = useCallback( const handleAccessUpdate = useCallback(
(s: AgeAssuranceState) => { (s: AgeAssuranceState) => {
void getAndRegisterPushToken({ const isAgeRestricted = s.access !== AgeAssuranceAccess.Full
isAgeRestricted: s.access !== AgeAssuranceAccess.Full, if (isAgeRestricted) {
}) void getAndRegisterPushToken({isAgeRestricted})
maybeRestrictChatSettings({agent})
}
}, },
[getAndRegisterPushToken], [agent, getAndRegisterPushToken],
) )
useOnAgeAssuranceAccessUpdate(handleAccessUpdate) useOnAgeAssuranceAccessUpdate(handleAccessUpdate)
+79 -10
View File
@@ -1,8 +1,15 @@
import {useEffect, useMemo, useState} from 'react' import {useEffect, useMemo, useState} from 'react'
import {computeAgeAssuranceRegionAccess} from '@atproto/api' import {computeAgeAssuranceRegionAccess} from '@atproto/api'
import {getAge} from '#/lib/strings/time'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {useAgeAssuranceDataContext} from '#/ageAssurance/data' import {
type AgeAssuranceData,
getConfigFromCache,
getOtherRequiredDataFromCache,
getServerStateFromCache,
useAgeAssuranceDataContext,
} from '#/ageAssurance/data'
import {logger} from '#/ageAssurance/logger' import {logger} from '#/ageAssurance/logger'
import { import {
AgeAssuranceAccess, AgeAssuranceAccess,
@@ -12,14 +19,27 @@ import {
parseStatusFromString, parseStatusFromString,
} from '#/ageAssurance/types' } from '#/ageAssurance/types'
import {getAgeAssuranceRegionConfigWithFallback} from '#/ageAssurance/util' import {getAgeAssuranceRegionConfigWithFallback} from '#/ageAssurance/util'
import {useGeolocation} from '#/geolocation' import {type Geolocation, useGeolocation} from '#/geolocation'
import {device} from '#/storage'
export function useAgeAssuranceState(): AgeAssuranceState { /**
const {hasSession} = useSession() * Get final evaluated age assurance state. Handles fallbacks and defers to
const geolocation = useGeolocation() * server state before computing access based on AA config from the server +
const {config, state, data} = useAgeAssuranceDataContext() * geolocation and other data.
*/
return useMemo(() => { export function computeAgeAssuranceState({
hasSession,
config,
geolocation,
state,
data,
}: {
hasSession: boolean
config: AgeAssuranceData['config']
geolocation: Geolocation
state: AgeAssuranceData['state']
data: AgeAssuranceData['data']
}) {
/** /**
* This is where we control logged-out moderation prefs. It's all * This is where we control logged-out moderation prefs. It's all
* downstream of AA now. * downstream of AA now.
@@ -42,7 +62,7 @@ export function useAgeAssuranceState(): AgeAssuranceState {
return { return {
status: AgeAssuranceStatus.Unknown, status: AgeAssuranceStatus.Unknown,
access: AgeAssuranceAccess.Safe, access: AgeAssuranceAccess.Safe,
error: 'config', error: 'config' as const,
} }
} }
@@ -87,7 +107,56 @@ export function useAgeAssuranceState(): AgeAssuranceState {
computed, computed,
}) })
return computed return computed
}, [hasSession, geolocation, config, state, data]) }
/**
* This is a last-ditch helper for out-of-band reads of the AA state, such as
* during account creation. Don't use it for anything else.
*/
export function getAndComputeAgeAssuranceState({did}: {did: string}) {
const config = getConfigFromCache()
const state = getServerStateFromCache({did})
const data = getOtherRequiredDataFromCache({did})
const geolocation = device.get(['mergedGeolocation'])
if (!geolocation || !config || !state || !data) {
return {
status: AgeAssuranceStatus.Unknown,
access: AgeAssuranceAccess.Safe,
}
}
return computeAgeAssuranceState({
hasSession: true,
config,
geolocation,
state: state.state,
data: {
accountCreatedAt: state.metadata?.accountCreatedAt,
declaredAge: data?.birthdate
? getAge(new Date(data.birthdate))
: undefined,
birthdate: data?.birthdate,
},
})
}
export function useAgeAssuranceState(): AgeAssuranceState {
const {hasSession} = useSession()
const geolocation = useGeolocation()
const {config, state, data} = useAgeAssuranceDataContext()
return useMemo(
() =>
computeAgeAssuranceState({
hasSession,
config,
geolocation,
state,
data,
}),
[hasSession, geolocation, config, state, data],
)
} }
export function useOnAgeAssuranceAccessUpdate( export function useOnAgeAssuranceAccessUpdate(
+20 -1
View File
@@ -2,13 +2,19 @@ import {useMemo} from 'react'
import { import {
ageAssuranceRuleIDs as ids, ageAssuranceRuleIDs as ids,
type AppBskyAgeassuranceDefs, type AppBskyAgeassuranceDefs,
type AtpAgent,
getAgeAssuranceRegionConfig, getAgeAssuranceRegionConfig,
type ModerationPrefs, type ModerationPrefs,
} from '@atproto/api' } from '@atproto/api'
import {getAge} from '#/lib/strings/time' import {getAge} from '#/lib/strings/time'
import {restrictChatSettings} from '#/state/queries/messages/restrictChatSettings'
import {DEFAULT_LOGGED_OUT_LABEL_PREFERENCES} from '#/state/queries/preferences/moderation' import {DEFAULT_LOGGED_OUT_LABEL_PREFERENCES} from '#/state/queries/preferences/moderation'
import {useAgeAssuranceDataContext} from '#/ageAssurance/data' import {
getDidFromAgentSession,
getOtherRequiredDataFromCache,
useAgeAssuranceDataContext,
} from '#/ageAssurance/data'
import {AgeAssuranceAccess} from '#/ageAssurance/types' import {AgeAssuranceAccess} from '#/ageAssurance/types'
import {type Geolocation, useGeolocation} from '#/geolocation' import {type Geolocation, useGeolocation} from '#/geolocation'
@@ -109,3 +115,16 @@ export const makeAgeRestrictedModerationPrefs = (
adultContentEnabled: false, adultContentEnabled: false,
labels: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES, labels: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES,
}) })
/**
* Checks our cache of the actor's chat declaration record, and if it's not
* already restricted, restricts it.
*/
export function maybeRestrictChatSettings({agent}: {agent: AtpAgent}) {
const did = getDidFromAgentSession(agent)
if (!did) return
const data = getOtherRequiredDataFromCache({did})
// ...update the chat setting record if allowIncoming is not already 'none'.
if (data?.actorDeclaration?.allowIncoming === 'none') return
restrictChatSettings({agent, did})
}
+17 -23
View File
@@ -1,8 +1,6 @@
import {useCallback, useMemo, useState} from 'react' import {useCallback, useMemo, useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/core/macro' import {Trans, useLingui} from '@lingui/react/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro'
import {useCleanError} from '#/lib/hooks/useCleanError' import {useCleanError} from '#/lib/hooks/useCleanError'
import {isAppPassword} from '#/lib/jwt' import {isAppPassword} from '#/lib/jwt'
@@ -34,7 +32,7 @@ export function BirthDateSettingsDialog({
control: Dialog.DialogControlProps control: Dialog.DialogControlProps
}) { }) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {t: l} = useLingui()
const {isLoading, error, data: preferences} = usePreferencesQuery() const {isLoading, error, data: preferences} = usePreferencesQuery()
const isBirthdateUpdateAllowed = useIsBirthdateUpdateAllowed() const isBirthdateUpdateAllowed = useIsBirthdateUpdateAllowed()
const {currentAccount} = useSession() const {currentAccount} = useSession()
@@ -45,11 +43,11 @@ export function BirthDateSettingsDialog({
<Dialog.Handle /> <Dialog.Handle />
{isBirthdateUpdateAllowed ? ( {isBirthdateUpdateAllowed ? (
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_(msg`My Birthdate`)} label={l`My birthdate`}
style={web({maxWidth: 400})}> style={web({maxWidth: 400})}>
<View style={[a.gap_md]}> <View style={[a.gap_md]}>
<Text style={[a.text_xl, a.font_semi_bold]}> <Text style={[a.text_xl, a.font_semi_bold]}>
<Trans>My Birthdate</Trans> <Trans>My birthdate</Trans>
</Text> </Text>
<Text <Text
style={[a.text_md, a.leading_snug, t.atoms.text_contrast_medium]}> style={[a.text_md, a.leading_snug, t.atoms.text_contrast_medium]}>
@@ -64,9 +62,7 @@ export function BirthDateSettingsDialog({
<ErrorMessage <ErrorMessage
message={ message={
error?.toString() || error?.toString() ||
_( l`We were unable to load your birthdate preferences. Please try again.`
msg`We were unable to load your birthdate preferences. Please try again.`,
)
} }
style={[a.rounded_sm]} style={[a.rounded_sm]}
/> />
@@ -88,7 +84,7 @@ export function BirthDateSettingsDialog({
</Dialog.ScrollableInner> </Dialog.ScrollableInner>
) : ( ) : (
<Dialog.ScrollableInner <Dialog.ScrollableInner
label={_(msg`You recently changed your birthdate`)} label={l`You recently changed your birthdate`}
style={web({maxWidth: 400})}> style={web({maxWidth: 400})}>
<View style={[a.gap_sm]}> <View style={[a.gap_sm]}>
<Text <Text
@@ -123,15 +119,16 @@ function BirthdayInner({
control: Dialog.DialogControlProps control: Dialog.DialogControlProps
preferences: UsePreferencesQueryResponse preferences: UsePreferencesQueryResponse
}) { }) {
const {_} = useLingui() const {t: l} = useLingui()
const cleanError = useCleanError() const cleanError = useCleanError()
const [date, setDate] = useState(preferences.birthDate || getDateAgo(18)) const [date, setDate] = useState(preferences.birthDate || getDateAgo(18))
const {isPending, error, mutateAsync: setBirthDate} = useBirthdateMutation() const {isPending, error, mutateAsync: setBirthDate} = useBirthdateMutation()
const hasChanged = date !== preferences.birthDate const hasChanged = date !== preferences.birthDate
const errorMessage = useMemo(() => { const errorMessage = useMemo(() => {
if (error) { if (error) {
const {raw, clean} = cleanError(error) const e = error as Error
return clean || raw || error.toString() const {raw, clean} = cleanError(e)
return clean || raw || e.toString()
} }
}, [error, cleanError]) }, [error, cleanError])
@@ -146,7 +143,8 @@ function BirthdayInner({
await setBirthDate({birthDate: date}) await setBirthDate({birthDate: date})
} }
control.close() control.close()
} catch (e: any) { } catch (error) {
const e = error as Error
logger.error(`setBirthDate failed`, {message: e.message}) logger.error(`setBirthDate failed`, {message: e.message})
} }
}, [date, setBirthDate, control, hasChanged]) }, [date, setBirthDate, control, hasChanged])
@@ -158,11 +156,10 @@ function BirthdayInner({
testID="birthdayInput" testID="birthdayInput"
value={date} value={date}
onChangeDate={newDate => setDate(new Date(newDate))} onChangeDate={newDate => setDate(new Date(newDate))}
label={_(msg`Birthdate`)} label={l`Birthdate`}
accessibilityHint={_(msg`Enter your birthdate`)} accessibilityHint={l`Enter your birthdate`}
/> />
</View> </View>
{isUnder18 && hasChanged && ( {isUnder18 && hasChanged && (
<Admonition type="info"> <Admonition type="info">
<Trans> <Trans>
@@ -171,30 +168,27 @@ function BirthdayInner({
</Trans> </Trans>
</Admonition> </Admonition>
)} )}
{isUnder13 && ( {isUnder13 && (
<Admonition type="error"> <Admonition type="error">
<Trans> <Trans>
You must be at least 13 years old to use Bluesky. Read our{' '} You must be at least 13 years old to use Bluesky. Read our{' '}
<SimpleInlineLinkText <SimpleInlineLinkText
to="https://bsky.social/about/support/tos" to="https://bsky.social/about/support/tos"
label={_(msg`Terms of Service`)}> label={l`Terms of Service`}>
Terms of Service Terms of Service
</SimpleInlineLinkText>{' '} </SimpleInlineLinkText>{' '}
for more information. for more information.
</Trans> </Trans>
</Admonition> </Admonition>
)} )}
{errorMessage ? ( {errorMessage ? (
<ErrorMessage message={errorMessage} style={[a.rounded_sm]} /> <ErrorMessage message={errorMessage} style={[a.rounded_sm]} />
) : undefined} ) : undefined}
<View style={IS_WEB && [a.flex_row, a.justify_end]}> <View style={IS_WEB && [a.flex_row, a.justify_end]}>
<Button <Button
label={hasChanged ? _(msg`Save birthdate`) : _(msg`Done`)} label={hasChanged ? l`Save birthdate` : l`Done`}
size="large" size="large"
onPress={onSave} onPress={() => void onSave()}
variant="solid" variant="solid"
color="primary" color="primary"
disabled={isUnder13}> disabled={isUnder13}>
+6
View File
@@ -4,6 +4,7 @@ import {useMutation, useQueryClient} from '@tanstack/react-query'
import {preferencesQueryKey} from '#/state/queries/preferences' import {preferencesQueryKey} from '#/state/queries/preferences'
import {useAgent, useSession} from '#/state/session' import {useAgent, useSession} from '#/state/session'
import {usePatchAgeAssuranceOtherRequiredData} from '#/ageAssurance' import {usePatchAgeAssuranceOtherRequiredData} from '#/ageAssurance'
import {isUnderAge, maybeRestrictChatSettings} from '#/ageAssurance/util'
import {IS_DEV} from '#/env' import {IS_DEV} from '#/env'
import {account} from '#/storage' import {account} from '#/storage'
@@ -63,6 +64,11 @@ export function useBirthdateMutation() {
await queryClient.invalidateQueries({ await queryClient.invalidateQueries({
queryKey: preferencesQueryKey, queryKey: preferencesQueryKey,
}) })
if (isUnderAge(birthDate.toISOString(), 18)) {
maybeRestrictChatSettings({agent})
}
/** /**
* Also patch the age assurance other required data with the new * Also patch the age assurance other required data with the new
* birthdate, which may change the user's age assurance access level. * birthdate, which may change the user's age assurance access level.
@@ -1,4 +1,8 @@
import {type AppBskyActorDefs} from '@atproto/api' import type AtpAgent from '@atproto/api'
import {
type AppBskyActorDefs,
type ChatBskyActorDeclaration,
} from '@atproto/api'
import {useMutation, useQueryClient} from '@tanstack/react-query' import {useMutation, useQueryClient} from '@tanstack/react-query'
import {logger} from '#/logger' import {logger} from '#/logger'
@@ -78,3 +82,21 @@ export function useDeleteActorDeclaration() {
}, },
}) })
} }
export async function fetchActorDeclarationRecord({
agent,
did,
}: {
agent: AtpAgent
did?: string
}) {
if (!did) return
const res = await agent.com.atproto.repo
.getRecord({
repo: did,
collection: 'chat.bsky.actor.declaration',
rkey: 'self',
})
.catch(_e => undefined)
return res?.data.value as ChatBskyActorDeclaration.Main
}
@@ -0,0 +1,39 @@
import type AtpAgent from '@atproto/api'
import {type ChatBskyActorDeclaration} from '@atproto/api'
import {networkRetry} from '#/lib/async/retry'
import {logger} from '#/logger'
import {setOtherRequiredDataActorDeclarationCache} from '#/ageAssurance/data'
/**
* Helper to update the chat settings record.
*/
export async function restrictChatSettings({
agent,
did,
}: {
agent: AtpAgent
did: string
}): Promise<void> {
try {
const record: ChatBskyActorDeclaration.Main = {
$type: 'chat.bsky.actor.declaration',
allowIncoming: 'none',
}
await networkRetry(3, () =>
agent.com.atproto.repo.putRecord({
repo: did,
collection: 'chat.bsky.actor.declaration',
rkey: 'self',
record,
}),
)
// important, update local cache to avoid running this again
setOtherRequiredDataActorDeclarationCache({
did,
actorDeclaration: record,
})
} catch {
logger.error(`restrictChatSettings: failed to set chat declaration`)
}
}
@@ -12,6 +12,9 @@ jest.mock('jwt-decode', () => ({
jest.mock('../../birthdate') jest.mock('../../birthdate')
jest.mock('../../../ageAssurance/data') jest.mock('../../../ageAssurance/data')
jest.mock('../../../ageAssurance/state', () => ({
getAndComputeAgeAssuranceState: () => ({}),
}))
jest.mock('#/lib/notifications/notifications', () => ({ jest.mock('#/lib/notifications/notifications', () => ({
unregisterPushToken(_agents: BskyAgent[]) { unregisterPushToken(_agents: BskyAgent[]) {
return Promise.resolve() return Promise.resolve()
+9 -20
View File
@@ -22,15 +22,17 @@ import {
PUBLIC_BSKY_SERVICE, PUBLIC_BSKY_SERVICE,
TIMELINE_SAVED_FEED, TIMELINE_SAVED_FEED,
} from '#/lib/constants' } from '#/lib/constants'
import {getAge} from '#/lib/strings/time'
import {logger} from '#/logger' import {logger} from '#/logger'
import {snoozeBirthdateUpdateAllowedForDid} from '#/state/birthdate' import {snoozeBirthdateUpdateAllowedForDid} from '#/state/birthdate'
import {restrictChatSettings} from '#/state/queries/messages/restrictChatSettings'
import {snoozeEmailConfirmationPrompt} from '#/state/shell/reminders' import {snoozeEmailConfirmationPrompt} from '#/state/shell/reminders'
import { import {
prefetchAgeAssuranceData, prefetchAgeAssuranceData,
setBirthdateForDid, setBirthdateForDid,
setCreatedAtForDid, setCreatedAtForDid,
} from '#/ageAssurance/data' } from '#/ageAssurance/data'
import {getAndComputeAgeAssuranceState} from '#/ageAssurance/state'
import {AgeAssuranceAccess} from '#/ageAssurance/types'
import {features} from '#/analytics' import {features} from '#/analytics'
import {emitNetworkConfirmed, emitNetworkLost} from '../events' import {emitNetworkConfirmed, emitNetworkLost} from '../events'
import {addSessionErrorLog} from './logging' import {addSessionErrorLog} from './logging'
@@ -218,26 +220,13 @@ export async function createAgentAndCreateAccount(
logger.info(`createAgentAndCreateAccount: failed to set initial feeds`) logger.info(`createAgentAndCreateAccount: failed to set initial feeds`)
throw e throw e
}), }),
...(getAge(birthDate) < 18 // wait for AA data to load first, then check state
? [ aa.then(async () => {
networkRetry(3, () => { const state = getAndComputeAgeAssuranceState({did: account.did})
return agent.com.atproto.repo.putRecord({ if (state.access !== AgeAssuranceAccess.Full) {
repo: account.did, restrictChatSettings({agent, did: account.did})
collection: 'chat.bsky.actor.declaration', }
rkey: 'self',
record: {
$type: 'chat.bsky.actor.declaration',
allowIncoming: 'none',
},
})
}).catch(e => {
logger.info(
`createAgentAndCreateAccount: failed to set chat declaration`,
)
throw e
}), }),
]
: []),
]).then(promises => { ]).then(promises => {
const rejected = promises.filter(p => p.status === 'rejected') const rejected = promises.filter(p => p.status === 'rejected')
if (rejected.length > 0) { if (rejected.length > 0) {