finish phase 3: type-only codemod and zero non-bridge @atproto/api imports

Task 8: codemod repointed 150 namespace-type files to #/lexicons
(AppBskyFeedDefs.PostView -> app.bsky.feed.defs.PostView, .Record -> .Main)
plus ~105 hand-fixed consumers (composer/video state, DebugMod, Profile,
onboarding, dialogs). DM_SERVICE_HEADERS deleted; last chat call sites on
the chat client. RichText.tsx flipped to SDK-only. Remaining @atproto/api
importers: the three session bridge files, the deliberate dual-world
matcher in lib/xrpc-error.ts, and test fixtures. toLex boundary casts are
TODO(phase4)-tagged for bridge removal.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Samuel Newman
2026-07-17 02:08:48 +03:00
parent 300a50b69a
commit e7d349bc30
283 changed files with 2029 additions and 1806 deletions
+6 -12
View File
@@ -1,8 +1,3 @@
import {
ageAssuranceRuleIDs as ids,
type AppBskyAgeassuranceDefs,
} from '@atproto/api'
import {AgeAssuranceAccess} from '#/ageAssurance/types'
import {
ANDROID_API_LEVEL,
@@ -11,6 +6,7 @@ import {
IS_IOS,
IS_WEB,
} from '#/env'
import {app} from '#/lexicons'
/**
* Minimum age required to access the app at all.
@@ -44,19 +40,17 @@ export const AGE_ASSURANCE_PLATFORM: 'web' | 'ios' | 'android' = IS_WEB
export const DEVICE_SIGNALS_SUPPORTED: boolean =
(IS_IOS && IOS_MAJOR_VERSION >= 26) || (IS_ANDROID && ANDROID_API_LEVEL >= 23)
export const FALLBACK_REGION_CONFIG: AppBskyAgeassuranceDefs.ConfigRegion = {
export const FALLBACK_REGION_CONFIG: app.bsky.ageassurance.defs.ConfigRegion = {
countryCode: '*',
regionCode: undefined,
minAccessAge: MIN_ACCESS_AGE,
rules: [
{
$type: ids.IfDeclaredOverAge,
app.bsky.ageassurance.defs.configRegionRuleIfDeclaredOverAge.build({
age: MIN_ACCESS_AGE,
access: AgeAssuranceAccess.Full,
},
{
$type: ids.Default,
}),
app.bsky.ageassurance.defs.configRegionRuleDefault.build({
access: AgeAssuranceAccess.None,
},
}),
],
}
+32 -28
View File
@@ -1,12 +1,6 @@
import {createContext, useCallback, useContext, useEffect, useMemo} from 'react'
import * as AgeRange from 'expo-age-range'
import {
type AppBskyAgeassuranceDefs,
type AppBskyAgeassuranceGetConfig,
type AppBskyAgeassuranceGetState,
AtpAgent,
type ChatBskyActorDeclaration,
} from '@atproto/api'
import {Client} from '@atproto/lex-client'
import {createAsyncStoragePersister} from '@tanstack/query-async-storage-persister'
import {focusManager, QueryClient, useQuery} from '@tanstack/react-query'
import {persistQueryClient} from '@tanstack/react-query-persist-client'
@@ -37,7 +31,9 @@ import {
} from '#/ageAssurance/util'
import {IS_DEV} from '#/env'
import {useGeolocation} from '#/geolocation'
import {app, type chat} from '#/lexicons'
import {device} from '#/storage'
import {toLex} from '#/types/bsky'
/**
* Special query client for age assurance data so we can prefetch on app
@@ -101,16 +97,15 @@ export function setBirthdateForDid({
export const configQueryKey = ['config']
export async function getConfig() {
if (debug.enabled) return debug.resolve(debug.config)
const agent = new AtpAgent({
const client = new Client({
service: PUBLIC_BSKY_SERVICE,
})
const res = await agent.app.bsky.ageassurance.getConfig()
return res.data
return await client.call(app.bsky.ageassurance.getConfig)
}
export function getConfigFromCache():
| AppBskyAgeassuranceGetConfig.OutputSchema
| app.bsky.ageassurance.getConfig.$OutputBody
| undefined {
return qc.getQueryData<AppBskyAgeassuranceGetConfig.OutputSchema>(
return qc.getQueryData<app.bsky.ageassurance.getConfig.$OutputBody>(
configQueryKey,
)
}
@@ -131,7 +126,7 @@ export function prefetchConfig() {
try {
logger.debug(`prefetchAgeAssuranceConfig: resolving...`)
const res = await networkRetry(3, () => getConfig())
qc.setQueryData<AppBskyAgeassuranceGetConfig.OutputSchema>(
qc.setQueryData<app.bsky.ageassurance.getConfig.$OutputBody>(
configQueryKey,
res,
)
@@ -147,7 +142,7 @@ export function prefetchConfig() {
export async function refetchConfig() {
logger.debug(`refetchConfig: fetching...`)
const res = await getConfig()
qc.setQueryData<AppBskyAgeassuranceGetConfig.OutputSchema>(
qc.setQueryData<app.bsky.ageassurance.getConfig.$OutputBody>(
configQueryKey,
res,
)
@@ -187,7 +182,11 @@ export function useConfigQuery() {
export function createServerStateQueryKey({did}: {did: string}) {
return ['serverState', did]
}
export async function getServerState({agent}: {agent: SessionAgent}) {
export async function getServerState({
agent,
}: {
agent: SessionAgent
}): Promise<app.bsky.ageassurance.getState.$OutputBody | null> {
if (debug.enabled && debug.serverState)
return debug.resolve(debug.serverState)
const geolocation = device.get(['mergedGeolocation'])
@@ -207,14 +206,19 @@ export async function getServerState({agent}: {agent: SessionAgent}) {
*/
data.metadata.accountCreatedAt = createdAtCache.get(did)
}
return data ?? null
/*
* TODO(phase4): the bridge agent still returns the old `@atproto/api`
* getState output; `toLex` reconciles it with the `#/lexicons` shape at this
* single boundary until the agent itself is migrated.
*/
return data ? toLex<app.bsky.ageassurance.getState.$OutputBody>(data) : null
}
export function getServerStateFromCache({
did,
}: {
did: string
}): AppBskyAgeassuranceGetState.OutputSchema | undefined {
return qc.getQueryData<AppBskyAgeassuranceGetState.OutputSchema>(
}): app.bsky.ageassurance.getState.$OutputBody | undefined {
return qc.getQueryData<app.bsky.ageassurance.getState.$OutputBody>(
createServerStateQueryKey({did}),
)
}
@@ -236,7 +240,7 @@ export async function prefetchServerState({agent}: {agent: SessionAgent}) {
logger.debug(`prefetchServerState: resolving...`)
const res = await networkRetry(3, () => getServerState({agent}))
if (res) {
qc.setQueryData<AppBskyAgeassuranceGetState.OutputSchema>(qk, res)
qc.setQueryData<app.bsky.ageassurance.getState.$OutputBody>(qk, res)
}
} catch (err) {
const e = err as Error
@@ -251,7 +255,7 @@ export async function refetchServerState({agent}: {agent: SessionAgent}) {
logger.debug(`refetchServerState: fetching...`)
const res = await networkRetry(3, () => getServerState({agent}))
if (res) {
qc.setQueryData<AppBskyAgeassuranceGetState.OutputSchema>(
qc.setQueryData<app.bsky.ageassurance.getState.$OutputBody>(
createServerStateQueryKey({did}),
res,
)
@@ -261,16 +265,16 @@ export async function refetchServerState({agent}: {agent: SessionAgent}) {
export function usePatchServerState() {
const {currentAccount} = useSession()
return useCallback(
(next: AppBskyAgeassuranceDefs.State) => {
(next: app.bsky.ageassurance.defs.State) => {
if (!currentAccount) return
const did = currentAccount.did
const prev = getServerStateFromCache({did})
const merged: AppBskyAgeassuranceGetState.OutputSchema = {
const merged: app.bsky.ageassurance.getState.$OutputBody = {
metadata: {},
...(prev || {}),
state: next,
}
qc.setQueryData<AppBskyAgeassuranceGetState.OutputSchema>(
qc.setQueryData<app.bsky.ageassurance.getState.$OutputBody>(
createServerStateQueryKey({did}),
merged,
)
@@ -336,7 +340,7 @@ export function useServerStateQuery() {
export type OtherRequiredData = {
birthdate: string | undefined
actorDeclaration?: ChatBskyActorDeclaration.Main
actorDeclaration?: chat.bsky.actor.declaration.Main
}
export function createOtherRequiredDataQueryKey({did}: {did: string}) {
return ['otherRequiredData', did]
@@ -411,7 +415,7 @@ export function setOtherRequiredDataActorDeclarationCache({
actorDeclaration,
}: {
did: string
actorDeclaration: ChatBskyActorDeclaration.Main
actorDeclaration: chat.bsky.actor.declaration.Main
}) {
const prev = getOtherRequiredDataFromCache({did})
const next: OtherRequiredData = {
@@ -551,7 +555,7 @@ export function getDeviceSignalsFromCacheForRegion({
region,
}: {
did: string
region: AppBskyAgeassuranceDefs.ConfigRegion
region: app.bsky.ageassurance.defs.ConfigRegion
}): AgeRange.AgeRangeResponse | undefined {
const regionKey = createRegionKey(region)
return getDeviceSignalsMapFromCache({did})?.[regionKey]
@@ -695,11 +699,11 @@ export type AgeAssuranceServerData = {
/**
* The raw config from the appview.
*/
config: AppBskyAgeassuranceDefs.Config | undefined
config: app.bsky.ageassurance.defs.Config | undefined
/**
* The raw state from the appview. Must be further processed before being useful.
*/
state: AppBskyAgeassuranceDefs.State | undefined
state: app.bsky.ageassurance.defs.State | undefined
metadata: AgeAssuranceMetadata | undefined
/**
* The native on-device age signals for the region the user is currently in,
+50 -51
View File
@@ -1,13 +1,10 @@
import type * as AgeRange from 'expo-age-range'
import {
ageAssuranceRuleIDs as ids,
type AppBskyAgeassuranceDefs,
type AppBskyAgeassuranceGetState,
} from '@atproto/api'
import {toDatetimeString} from '@atproto/syntax'
import {type OtherRequiredData} from '#/ageAssurance/data'
import {IS_DEV, IS_E2E} from '#/env'
import {type Geolocation} from '#/geolocation'
import {type app} from '#/lexicons'
export const enabled = (IS_DEV && false) || IS_E2E
@@ -31,21 +28,22 @@ export const otherRequiredData: OtherRequiredData = {
}
const serverStateEnabled = false || IS_E2E
export const serverState: AppBskyAgeassuranceGetState.OutputSchema | undefined =
serverStateEnabled
? {
state: {
lastInitiatedAt: undefined, // new Date(2025, 1, 1).toISOString(),
status: 'unknown',
access: 'unknown',
},
metadata: {
accountCreatedAt: new Date(2023, 1, 1).toISOString(),
},
}
: undefined
export const serverState:
| app.bsky.ageassurance.getState.$OutputBody
| undefined = serverStateEnabled
? {
state: {
lastInitiatedAt: undefined, // new Date(2025, 1, 1).toISOString(),
status: 'unknown',
access: 'unknown',
},
metadata: {
accountCreatedAt: toDatetimeString(new Date(2023, 1, 1)),
},
}
: undefined
export const config: AppBskyAgeassuranceDefs.Config = {
export const config: app.bsky.ageassurance.defs.Config = {
regions: [
{
countryCode: 'AA',
@@ -53,7 +51,7 @@ export const config: AppBskyAgeassuranceDefs.Config = {
minAccessAge: 13,
rules: [
{
$type: ids.Default,
$type: 'app.bsky.ageassurance.defs#configRegionRuleDefault',
access: 'full',
},
],
@@ -71,11 +69,11 @@ export const config: AppBskyAgeassuranceDefs.Config = {
{
age: 18,
access: 'full',
$type: ids.IfAssuredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfAssuredOverAge',
},
{
access: 'none',
$type: ids.Default,
$type: 'app.bsky.ageassurance.defs#configRegionRuleDefault',
},
],
},
@@ -86,16 +84,16 @@ export const config: AppBskyAgeassuranceDefs.Config = {
{
age: 18,
access: 'full',
$type: ids.IfAssuredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfAssuredOverAge',
},
{
age: 13,
access: 'safe',
$type: ids.IfDeclaredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfDeclaredOverAge',
},
{
access: 'none',
$type: ids.Default,
$type: 'app.bsky.ageassurance.defs#configRegionRuleDefault',
},
],
},
@@ -106,26 +104,27 @@ export const config: AppBskyAgeassuranceDefs.Config = {
{
date: '2025-12-10T00:00:00Z',
access: 'none',
$type: ids.IfAccountNewerThan,
$type:
'app.bsky.ageassurance.defs#configRegionRuleIfAccountNewerThan',
},
{
age: 18,
access: 'full',
$type: ids.IfAssuredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfAssuredOverAge',
},
{
age: 16,
access: 'safe',
$type: ids.IfAssuredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfAssuredOverAge',
},
{
age: 16,
access: 'safe',
$type: ids.IfDeclaredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfDeclaredOverAge',
},
{
access: 'none',
$type: ids.Default,
$type: 'app.bsky.ageassurance.defs#configRegionRuleDefault',
},
],
},
@@ -137,16 +136,16 @@ export const config: AppBskyAgeassuranceDefs.Config = {
{
age: 18,
access: 'full',
$type: ids.IfAssuredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfAssuredOverAge',
},
{
age: 13,
access: 'safe',
$type: ids.IfDeclaredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfDeclaredOverAge',
},
{
access: 'none',
$type: ids.Default,
$type: 'app.bsky.ageassurance.defs#configRegionRuleDefault',
},
],
},
@@ -158,16 +157,16 @@ export const config: AppBskyAgeassuranceDefs.Config = {
{
age: 18,
access: 'full',
$type: ids.IfAssuredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfAssuredOverAge',
},
{
age: 13,
access: 'safe',
$type: ids.IfDeclaredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfDeclaredOverAge',
},
{
access: 'none',
$type: ids.Default,
$type: 'app.bsky.ageassurance.defs#configRegionRuleDefault',
},
],
},
@@ -179,16 +178,16 @@ export const config: AppBskyAgeassuranceDefs.Config = {
{
age: 18,
access: 'full',
$type: ids.IfAssuredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfAssuredOverAge',
},
{
age: 13,
access: 'safe',
$type: ids.IfDeclaredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfDeclaredOverAge',
},
{
access: 'none',
$type: ids.Default,
$type: 'app.bsky.ageassurance.defs#configRegionRuleDefault',
},
],
},
@@ -200,11 +199,11 @@ export const config: AppBskyAgeassuranceDefs.Config = {
{
age: 18,
access: 'full',
$type: ids.IfAssuredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfAssuredOverAge',
},
{
access: 'none',
$type: ids.Default,
$type: 'app.bsky.ageassurance.defs#configRegionRuleDefault',
},
],
},
@@ -216,16 +215,16 @@ export const config: AppBskyAgeassuranceDefs.Config = {
{
age: 16,
access: 'full',
$type: ids.IfAssuredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfAssuredOverAge',
},
{
age: 16,
access: 'full',
$type: ids.IfDeclaredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfDeclaredOverAge',
},
{
access: 'none',
$type: ids.Default,
$type: 'app.bsky.ageassurance.defs#configRegionRuleDefault',
},
],
},
@@ -237,16 +236,16 @@ export const config: AppBskyAgeassuranceDefs.Config = {
{
age: 18,
access: 'full',
$type: ids.IfAssuredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfAssuredOverAge',
},
{
age: 18,
access: 'full',
$type: ids.IfDeclaredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfDeclaredOverAge',
},
{
access: 'none',
$type: ids.Default,
$type: 'app.bsky.ageassurance.defs#configRegionRuleDefault',
},
],
},
@@ -257,21 +256,21 @@ export const config: AppBskyAgeassuranceDefs.Config = {
{
age: 18,
access: 'full',
$type: ids.IfAssuredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfAssuredOverAge',
},
{
age: 18,
access: 'full',
$type: ids.IfDeclaredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfDeclaredOverAge',
},
{
age: 13,
access: 'safe',
$type: ids.IfDeclaredOverAge,
$type: 'app.bsky.ageassurance.defs#configRegionRuleIfDeclaredOverAge',
},
{
access: 'none',
$type: ids.Default,
$type: 'app.bsky.ageassurance.defs#configRegionRuleDefault',
},
],
},
+4 -6
View File
@@ -1,9 +1,6 @@
import {useEffect, useMemo, useState} from 'react'
import type * as AgeRange from 'expo-age-range'
import {
type AppBskyAgeassuranceDefs,
computeAgeAssuranceRegionAccess,
} from '@atproto/api'
import {computeAgeAssuranceRegionAccess} from '@bsky.app/sdk/utils'
import {getAge} from '#/lib/strings/time'
import {useSession} from '#/state/session'
@@ -30,6 +27,7 @@ import {
getAgeAssuranceRegionConfigWithFallback,
} from '#/ageAssurance/util'
import {type Geolocation, useGeolocation} from '#/geolocation'
import {type app} from '#/lexicons'
import {device} from '#/storage'
/**
@@ -47,8 +45,8 @@ function computeAgeAssuranceState({
}: {
hasSession: boolean
geolocation: Geolocation
config?: AppBskyAgeassuranceDefs.Config
state?: AppBskyAgeassuranceDefs.State
config?: app.bsky.ageassurance.defs.Config
state?: app.bsky.ageassurance.defs.State
metadata?: AgeAssuranceMetadata
deviceSignals?: AgeRange.AgeRangeResponse
}) {
+1 -1
View File
@@ -1,5 +1,5 @@
import type * as AgeRange from 'expo-age-range'
import {type computeAgeAssuranceRegionAccess} from '@atproto/api'
import {type computeAgeAssuranceRegionAccess} from '@bsky.app/sdk/utils'
import {logger} from '#/ageAssurance/logger'
@@ -1,5 +1,5 @@
import {useCallback} from 'react'
import {computeAgeAssuranceRegionAccess} from '@atproto/api'
import {computeAgeAssuranceRegionAccess} from '@bsky.app/sdk/utils'
import {useAgeAssuranceServerDataContext} from '#/ageAssurance/data'
import {logger} from '#/ageAssurance/logger'
+19 -15
View File
@@ -1,11 +1,10 @@
import {useMemo} from 'react'
import type * as AgeRange from 'expo-age-range'
import {type ModerationPrefs} from '@bsky.app/sdk/moderation'
import {
AppBskyAgeassuranceDefs,
computeAgeAssuranceRegionAccess,
getAgeAssuranceRegionConfig,
type ModerationPrefs,
} from '@atproto/api'
} from '@bsky.app/sdk/utils'
import {getAge} from '#/lib/strings/time'
import {regionName} from '#/locale/helpers'
@@ -25,6 +24,7 @@ import {
} from '#/ageAssurance/types'
import {type Geolocation, useGeolocation} from '#/geolocation'
import {USRegionNameToRegionCode} from '#/geolocation/util'
import {app} from '#/lexicons'
/**
* Resolves a geolocation to its matched age assurance region config, or
@@ -41,9 +41,9 @@ import {USRegionNameToRegionCode} from '#/geolocation/util'
* risk desyncing the write and read keys and silently losing grants.
*/
export function getAgeAssuranceRegionConfigForGeolocation(
config: AppBskyAgeassuranceDefs.Config,
config: app.bsky.ageassurance.defs.Config,
geolocation: Geolocation,
): AppBskyAgeassuranceDefs.ConfigRegion | undefined {
): app.bsky.ageassurance.defs.ConfigRegion | undefined {
return getAgeAssuranceRegionConfig(config, {
countryCode: geolocation.countryCode ?? '',
regionCode: geolocation.regionCode,
@@ -59,9 +59,9 @@ export function getAgeAssuranceRegionConfigForGeolocation(
* which can return undefined if the geolocation does not match any AA region.
*/
export function getAgeAssuranceRegionConfigWithFallback(
config: AppBskyAgeassuranceDefs.Config,
config: app.bsky.ageassurance.defs.Config,
geolocation: Geolocation,
): AppBskyAgeassuranceDefs.ConfigRegion {
): app.bsky.ageassurance.defs.ConfigRegion {
return (
getAgeAssuranceRegionConfigForGeolocation(config, geolocation) ||
FALLBACK_REGION_CONFIG
@@ -74,9 +74,9 @@ export function getAgeAssuranceRegionConfigWithFallback(
* historical KWS-only behavior).
*/
export function getRegionAdditionalVerificationMethods(
region: AppBskyAgeassuranceDefs.ConfigRegion,
region: app.bsky.ageassurance.defs.ConfigRegion,
): NonNullable<
AppBskyAgeassuranceDefs.ConfigRegion['additionalVerificationMethods']
app.bsky.ageassurance.defs.ConfigRegion['additionalVerificationMethods']
> {
return region.additionalVerificationMethods ?? []
}
@@ -86,7 +86,7 @@ export function getRegionAdditionalVerificationMethods(
* age APIs (Apple Declared Age Range / Google Play Age Signals).
*/
export function regionAllowsDeviceVerification(
region: AppBskyAgeassuranceDefs.ConfigRegion,
region: app.bsky.ageassurance.defs.ConfigRegion,
): boolean {
return getRegionAdditionalVerificationMethods(region).includes('device')
}
@@ -122,7 +122,7 @@ export function createRegionKey(region: {
* usable data.
*/
export function getAgeAssuranceDataFromDeviceSignals(
region: AppBskyAgeassuranceDefs.ConfigRegion,
region: app.bsky.ageassurance.defs.ConfigRegion,
deviceSignals: AgeRange.AgeRangeResponse | undefined,
): {
assuredAge?: number
@@ -183,7 +183,7 @@ export function canBirthdateUpdateIncreaseAccess({
metadata,
deviceSignals,
}: {
region: AppBskyAgeassuranceDefs.ConfigRegion
region: app.bsky.ageassurance.defs.ConfigRegion
metadata?: AgeAssuranceMetadata
deviceSignals?: AgeRange.AgeRangeResponse
}): boolean {
@@ -212,8 +212,12 @@ export function canBirthdateUpdateIncreaseAccess({
const thresholds = new Set<number>([region.minAccessAge])
for (const rule of region.rules) {
if (
AppBskyAgeassuranceDefs.isConfigRegionRuleIfDeclaredOverAge(rule) ||
AppBskyAgeassuranceDefs.isConfigRegionRuleIfDeclaredUnderAge(rule)
app.bsky.ageassurance.defs.configRegionRuleIfDeclaredOverAge.$isTypeOf(
rule,
) ||
app.bsky.ageassurance.defs.configRegionRuleIfDeclaredUnderAge.$isTypeOf(
rule,
)
) {
thresholds.add(rule.age)
}
@@ -303,7 +307,7 @@ export function computeAgeAssuranceFlags({
deviceSignals,
}: {
state: AgeAssuranceState
regionConfig: AppBskyAgeassuranceDefs.ConfigRegion
regionConfig: app.bsky.ageassurance.defs.ConfigRegion
metadata?: AgeAssuranceMetadata
deviceSignals?: AgeRange.AgeRangeResponse
}): AgeAssuranceFlags {