replace the age assurance agent clone with a token-scoped client
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
import {Platform} from 'react-native'
|
import {Platform} from 'react-native'
|
||||||
import {type AppBskyAgeassuranceBegin, AtpAgent} from '@atproto/api'
|
|
||||||
import {useMutation} from '@tanstack/react-query'
|
import {useMutation} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {wait} from '#/lib/async/wait'
|
import {wait} from '#/lib/async/wait'
|
||||||
@@ -9,26 +8,28 @@ import {
|
|||||||
PUBLIC_APPVIEW_DID,
|
PUBLIC_APPVIEW_DID,
|
||||||
} from '#/lib/constants'
|
} from '#/lib/constants'
|
||||||
import {isNetworkError} from '#/lib/hooks/useCleanError'
|
import {isNetworkError} from '#/lib/hooks/useCleanError'
|
||||||
import {useAgent} from '#/state/session'
|
import {createLexClient} from '#/lib/lexClient'
|
||||||
|
import {usePdsClient} from '#/state/session'
|
||||||
import {usePatchAgeAssuranceServerState} from '#/ageAssurance'
|
import {usePatchAgeAssuranceServerState} from '#/ageAssurance'
|
||||||
import {logger} from '#/ageAssurance/logger'
|
import {logger} from '#/ageAssurance/logger'
|
||||||
import {useAnalytics} from '#/analytics'
|
import {useAnalytics} from '#/analytics'
|
||||||
import {BLUESKY_PROXY_DID} from '#/env'
|
import {BLUESKY_PROXY_DID} from '#/env'
|
||||||
import {useGeolocation} from '#/geolocation'
|
import {useGeolocation} from '#/geolocation'
|
||||||
|
import {app, com} from '#/lexicons'
|
||||||
|
|
||||||
const IS_DEV_ENV = BLUESKY_PROXY_DID !== PUBLIC_APPVIEW_DID
|
const IS_DEV_ENV = BLUESKY_PROXY_DID !== PUBLIC_APPVIEW_DID
|
||||||
const APPVIEW = IS_DEV_ENV ? DEV_ENV_APPVIEW : PUBLIC_APPVIEW
|
const APPVIEW = IS_DEV_ENV ? DEV_ENV_APPVIEW : PUBLIC_APPVIEW
|
||||||
|
|
||||||
export function useBeginAgeAssurance() {
|
export function useBeginAgeAssurance() {
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
const agent = useAgent()
|
const pdsClient = usePdsClient()
|
||||||
const geolocation = useGeolocation()
|
const geolocation = useGeolocation()
|
||||||
const patchAgeAssuranceStateResponse = usePatchAgeAssuranceServerState()
|
const patchAgeAssuranceStateResponse = usePatchAgeAssuranceServerState()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
async mutationFn(
|
async mutationFn(
|
||||||
props: Omit<
|
props: Omit<
|
||||||
AppBskyAgeassuranceBegin.InputSchema,
|
app.bsky.ageassurance.begin.$InputBody,
|
||||||
'countryCode' | 'regionCode'
|
'countryCode' | 'regionCode'
|
||||||
>,
|
>,
|
||||||
) {
|
) {
|
||||||
@@ -38,17 +39,22 @@ export function useBeginAgeAssurance() {
|
|||||||
throw new Error(`Geolocation not available, cannot init age assurance.`)
|
throw new Error(`Geolocation not available, cannot init age assurance.`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {token} = await pdsClient.call(com.atproto.server.getServiceAuth, {
|
||||||
data: {token},
|
|
||||||
} = await agent.com.atproto.server.getServiceAuth({
|
|
||||||
aud: BLUESKY_PROXY_DID,
|
aud: BLUESKY_PROXY_DID,
|
||||||
lxm: `app.bsky.ageassurance.begin`,
|
lxm: `app.bsky.ageassurance.begin`,
|
||||||
})
|
})
|
||||||
|
|
||||||
const appView = new AtpAgent({service: APPVIEW})
|
/*
|
||||||
appView.sessionManager.session = {...agent.session!}
|
* A single-use client scoped to the service-auth token: it has no session,
|
||||||
appView.sessionManager.session.accessJwt = token
|
* so nothing can refresh it, and the request goes straight to the appview
|
||||||
appView.sessionManager.session.refreshJwt = ''
|
* with the token as a static `authorization` header. A raw client is
|
||||||
|
* allowed to preset that header where a session-backed one is not, which
|
||||||
|
* also makes the old `refreshJwt = ''` clone unnecessary.
|
||||||
|
*/
|
||||||
|
const scopedClient = createLexClient({
|
||||||
|
service: APPVIEW,
|
||||||
|
headers: {authorization: `Bearer ${token}`},
|
||||||
|
})
|
||||||
|
|
||||||
ax.metric('ageAssurance:api:begin', {
|
ax.metric('ageAssurance:api:begin', {
|
||||||
platform: Platform.OS,
|
platform: Platform.OS,
|
||||||
@@ -60,9 +66,9 @@ export function useBeginAgeAssurance() {
|
|||||||
* 2s wait is good actually. Email sending takes a hot sec and this helps
|
* 2s wait is good actually. Email sending takes a hot sec and this helps
|
||||||
* ensure the email is ready for the user once they open their inbox.
|
* ensure the email is ready for the user once they open their inbox.
|
||||||
*/
|
*/
|
||||||
const {data} = await wait(
|
const data = await wait(
|
||||||
2e3,
|
2e3,
|
||||||
appView.app.bsky.ageassurance.begin({
|
scopedClient.call(app.bsky.ageassurance.begin, {
|
||||||
...props,
|
...props,
|
||||||
countryCode,
|
countryCode,
|
||||||
regionCode,
|
regionCode,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {useState} from 'react'
|
import {useState} from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {XRPCError} from '@atproto/api'
|
import {XrpcResponseError} from '@atproto/lex'
|
||||||
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'
|
||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
import {useGetTimeAgo} from '#/lib/hooks/useTimeAgo'
|
import {useGetTimeAgo} from '#/lib/hooks/useTimeAgo'
|
||||||
import {useTLDs} from '#/lib/hooks/useTLDs'
|
import {useTLDs} from '#/lib/hooks/useTLDs'
|
||||||
import {isEmailMaybeInvalid} from '#/lib/strings/email'
|
import {isEmailMaybeInvalid} from '#/lib/strings/email'
|
||||||
|
import {matchXrpcError} from '#/lib/xrpc-error'
|
||||||
import {type AppLanguage} from '#/locale/languages'
|
import {type AppLanguage} from '#/locale/languages'
|
||||||
import {useLanguagePrefs} from '#/state/preferences'
|
import {useLanguagePrefs} from '#/state/preferences'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
@@ -33,6 +34,7 @@ import {Text} from '#/components/Typography'
|
|||||||
import {useAgeAssurance} from '#/ageAssurance'
|
import {useAgeAssurance} from '#/ageAssurance'
|
||||||
import {useBeginAgeAssurance} from '#/ageAssurance/useBeginAgeAssurance'
|
import {useBeginAgeAssurance} from '#/ageAssurance/useBeginAgeAssurance'
|
||||||
import {useAnalytics} from '#/analytics'
|
import {useAnalytics} from '#/analytics'
|
||||||
|
import {app} from '#/lexicons'
|
||||||
|
|
||||||
export {useDialogControl} from '#/components/Dialog/context'
|
export {useDialogControl} from '#/components/Dialog/context'
|
||||||
|
|
||||||
@@ -139,30 +141,37 @@ function Inner() {
|
|||||||
msg`Something went wrong, please try again`,
|
msg`Something went wrong, please try again`,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (e instanceof XRPCError) {
|
if (e instanceof XrpcResponseError) {
|
||||||
if (e.error === 'InvalidEmail') {
|
switch (matchXrpcError(e, app.bsky.ageassurance.begin)) {
|
||||||
error = _(
|
case 'InvalidEmail':
|
||||||
msg`Please enter a valid, non-temporary email address. You may need to access this email in the future.`,
|
error = _(
|
||||||
)
|
msg`Please enter a valid, non-temporary email address. You may need to access this email in the future.`,
|
||||||
ax.metric('ageAssurance:initDialogError', {code: 'InvalidEmail'})
|
)
|
||||||
} else if (e.error === 'DidTooLong') {
|
ax.metric('ageAssurance:initDialogError', {code: 'InvalidEmail'})
|
||||||
error = (
|
break
|
||||||
<>
|
case 'DidTooLong':
|
||||||
<Trans>
|
error = (
|
||||||
We're having issues initializing the age assurance process for
|
<>
|
||||||
your account. Please{' '}
|
<Trans>
|
||||||
<SimpleInlineLinkText
|
We're having issues initializing the age assurance process for
|
||||||
to={createSupportLink({code: SupportCode.AA_DID, email})}
|
your account. Please{' '}
|
||||||
label={_(msg`Contact support`)}>
|
<SimpleInlineLinkText
|
||||||
contact support
|
to={createSupportLink({code: SupportCode.AA_DID, email})}
|
||||||
</SimpleInlineLinkText>{' '}
|
label={_(msg`Contact support`)}>
|
||||||
for assistance.
|
contact support
|
||||||
</Trans>
|
</SimpleInlineLinkText>{' '}
|
||||||
</>
|
for assistance.
|
||||||
)
|
</Trans>
|
||||||
ax.metric('ageAssurance:initDialogError', {code: 'DidTooLong'})
|
</>
|
||||||
} else {
|
)
|
||||||
ax.metric('ageAssurance:initDialogError', {code: 'other'})
|
ax.metric('ageAssurance:initDialogError', {code: 'DidTooLong'})
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
/*
|
||||||
|
* An undeclared code keeps the generic message rather than surfacing
|
||||||
|
* the server's text, as the old `e.error` fallthrough did.
|
||||||
|
*/
|
||||||
|
ax.metric('ageAssurance:initDialogError', {code: 'other'})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const {clean, raw} = cleanError(e)
|
const {clean, raw} = cleanError(e)
|
||||||
|
|||||||
Reference in New Issue
Block a user