repoint the last AtpAgent statics and drop the dead conversions

Five sites read `AtpAgent.appLabelers`, which the previous commit stopped
populating - a silent regression, since an empty static reads as "no
authorities" rather than failing. All now read `Client.appLabelers`, the static
that is actually configured:

- `lib/moderation.ts`'s `isAppLabeler`, which decides whether a labeler is
  non-removable in the UI;
- `preferences/moderation.ts`'s `useMyLabelersQuery`, which seeds the labeler
  list with the app authorities;
- `feed/custom.ts`'s hand-rolled logged-out `getFeed`, which reproduces the
  header lex would have emitted because the request bypasses the client.

`sessionAccountToSession` (the `AtpSessionData` conversion) had no callers left
once the bridge agent went, and the age assurance config read - the one
standalone `new AtpAgent` the age assurance slice deliberately left behind -
moves to the public appview client, which is what it was approximating.

That is the last `AtpAgent` in src. What remains of `@atproto/api` in the
session layer is types and `BSKY_LABELER_DID`, which S4d owns.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Samuel Newman
2026-08-04 03:47:38 +03:00
parent 64b0039c67
commit 2f482f2c0b
5 changed files with 22 additions and 40 deletions
+9 -7
View File
@@ -4,7 +4,6 @@ import {
type AppBskyAgeassuranceDefs,
type AppBskyAgeassuranceGetConfig,
type AppBskyAgeassuranceGetState,
AtpAgent,
type ChatBskyActorDeclaration,
} from '@atproto/api'
import {type Client} from '@atproto/lex'
@@ -15,7 +14,6 @@ import {persistQueryClient} from '@tanstack/react-query-persist-client'
import debounce from 'lodash.debounce'
import {networkRetry} from '#/lib/async/retry'
import {PUBLIC_BSKY_SERVICE} from '#/lib/constants'
import {createPersistedQueryStorage} from '#/lib/persisted-query-storage'
import {getAge} from '#/lib/strings/time'
import {
@@ -24,6 +22,7 @@ import {
} from '#/state/birthdate'
import {fetchActorDeclarationRecord} from '#/state/queries/messages/actor-declaration'
import {useAppviewClient, usePdsClient, useSession} from '#/state/session'
import {getPublicAppviewClient} from '#/state/session/clients'
import {DEVICE_SIGNALS_SUPPORTED} from '#/ageAssurance/const'
import * as debug from '#/ageAssurance/debug'
import {logger} from '#/ageAssurance/logger'
@@ -98,11 +97,14 @@ export function setBirthdateForDid({
export const configQueryKey = ['config']
export async function getConfig() {
if (debug.enabled) return debug.resolve(debug.config)
const agent = new AtpAgent({
service: PUBLIC_BSKY_SERVICE,
})
const res = await agent.app.bsky.ageassurance.getConfig()
return res.data
/*
* An unauthenticated read against the public appview: the config is fetched
* before there is any session (and while logged out), so it goes through the
* process-wide public client rather than a bundle one.
*/
return (await getPublicAppviewClient().call(
app.bsky.ageassurance.getConfig,
)) as AppBskyAgeassuranceGetConfig.OutputSchema
}
export function getConfigFromCache():
| AppBskyAgeassuranceGetConfig.OutputSchema
+6 -6
View File
@@ -1,5 +1,5 @@
import {type AppBskyFeedDefs, AtpAgent, jsonStringToLex} from '@atproto/api'
import {type Client, type XrpcRequestParams} from '@atproto/lex'
import {type AppBskyFeedDefs, jsonStringToLex} from '@atproto/api'
import {Client, type XrpcRequestParams} from '@atproto/lex'
import {
getAppLanguageAsContentLanguage,
@@ -115,12 +115,12 @@ async function loggedOutFetch({
}): Promise<app.bsky.feed.getFeed.$OutputBody | null> {
let contentLangs = getAppLanguageAsContentLanguage()
/**
* Copied from our root `Agent` class
* @see https://github.com/bluesky-social/atproto/blob/60df3fc652b00cdff71dd9235d98a7a4bb828f05/packages/api/src/agent.ts#L120
/*
* This request is hand-rolled rather than issued through a client, so it has
* to reproduce the header lex would have emitted from the global static.
*/
const labelersHeader = {
'atproto-accept-labelers': AtpAgent.appLabelers
'atproto-accept-labelers': Client.appLabelers
.map(l => `${l};redact`)
.join(', '),
}
+5 -3
View File
@@ -1,5 +1,7 @@
import {useMemo} from 'react'
import {AtpAgent, type ComAtprotoLabelDefs} from '@atproto/api'
import {type ComAtprotoLabelDefs} from '@atproto/api'
import {Client} from '@atproto/lex'
import {type DidString} from '@atproto/syntax'
import {
type InterpretedLabelValueDefinition,
LABELS,
@@ -105,9 +107,9 @@ export function isAppLabeler(
| app.bsky.labeler.defs.LabelerViewDetailed,
): boolean {
if (typeof labeler === 'string') {
return AtpAgent.appLabelers.includes(labeler)
return Client.appLabelers.includes(labeler as DidString)
}
return AtpAgent.appLabelers.includes(labeler.creator.did)
return Client.appLabelers.includes(labeler.creator.did)
}
export function isLabelerSubscribed(
+2 -2
View File
@@ -1,5 +1,5 @@
import {useMemo} from 'react'
import {AtpAgent} from '@atproto/api'
import {Client} from '@atproto/lex'
import {interpretLabelValueDefinitions} from '@bsky.app/sdk/moderation'
import {isNonConfigurableModerationAuthority} from '#/state/session/additional-moderation-authorities'
@@ -14,7 +14,7 @@ export function useMyLabelersQuery({
const prefs = usePreferencesQuery()
let dids = Array.from(
new Set(
AtpAgent.appLabelers.concat(
(Client.appLabelers as readonly string[]).concat(
prefs.data?.moderationPrefs.labelers.map(l => l.did) || [],
),
),
-22
View File
@@ -1,4 +1,3 @@
import {type AtpSessionData} from '@atproto/api'
import {getPdsEndpoint, isValidDidDoc} from '@atproto/common-web'
import {type SessionData} from '@atproto/lex-password-session'
import {jwtDecode} from 'jwt-decode'
@@ -81,27 +80,6 @@ export function sessionAccountToSessionData(
}
}
/** Convert a persisted account into data suitable for `AtpAgent`. */
export function sessionAccountToSession(
account: SessionAccount,
): AtpSessionData {
return {
// Sorted in the same property order as when returned by BskyAgent (alphabetical).
accessJwt: account.accessJwt ?? '',
did: account.did,
email: account.email,
emailAuthFactor: account.emailAuthFactor,
emailConfirmed: account.emailConfirmed,
handle: account.handle,
refreshJwt: account.refreshJwt ?? '',
/**
* @see https://github.com/bluesky-social/atproto/blob/c5d36d5ba2a2c2a5c4f366a5621c06a5608e361e/packages/api/src/agent.ts#L188
*/
active: account.active ?? true,
status: account.status,
}
}
export function isSessionExpired(account: SessionAccount) {
return account.accessJwt ? isJwtExpired(account.accessJwt) : true
}