set the global app labelers on the lex Client static
`configureGlobalAppLabelers` now writes both `AtpAgent.configure` and `Client.configure`, so a client built without a wrapped agent carries the global `;redact` moderation authorities. That is what the logged-out appview client needs: it has no agent underneath to stamp the header, and after the bundle rework no client will. Flipping the static alone double-emits, which two probe runs confirmed. Neither producer dedupes against the other - the agent joins its list with whatever is already on the request while lex collects into a `Set` keyed on the `;redact`-suffixed string - so a DID in both statics produced `did:plc:x;redact, did:plc:x;redact`. Separately, the PDS and chat clients wrap the session manager *below* the agent's header layer and so emitted no labelers at all; the static would have started adding them to non-appview requests. Both are closed by building the three agent-wrapping clients with `appLabelers: null`, which suppresses the class-wide static per instance. That leaves exactly one producer on an appview request and none on a PDS or chat one, while the static stays populated for the clients that read only it. The labeler-header tests cover all three surfaces and fail without the suppression. The per-account subscriptions stay on the agent for now, behind `applyLabelersToClient`, because the agent is still what stamps the header on the wrapping client's requests. The bundle-rework slice repoints that one function body at `appviewClient.setLabelers` and drops the agent statics; the `Client.configure` half of `configureGlobalAppLabelers` and the `appLabelers: null` on the appview client both stay as they are. `configureModerationForAccount` takes the bundle rather than a bare agent, matching the signature the bundle rework needs.
This commit is contained in:
@@ -40,7 +40,7 @@ import {
|
|||||||
} from '#/state/queries/preferences/types'
|
} from '#/state/queries/preferences/types'
|
||||||
import {createQueryKey} from '#/state/queries/util'
|
import {createQueryKey} from '#/state/queries/util'
|
||||||
import {useAgent, usePdsClient} from '#/state/session'
|
import {useAgent, usePdsClient} from '#/state/session'
|
||||||
import {saveLabelers} from '#/state/session/moderation'
|
import {applyLabelersToClient, 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'
|
||||||
@@ -81,12 +81,17 @@ export function usePreferencesQuery() {
|
|||||||
/*
|
/*
|
||||||
* `BskyAgent.getPreferences` used to call `configureLabelers` itself,
|
* `BskyAgent.getPreferences` used to call `configureLabelers` itself,
|
||||||
* so subscribing to a labeler took effect on the very next appview
|
* 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
|
* read. The sdk action has no such side effect, so apply the
|
||||||
* inherit `atproto-accept-labelers` from the agent's fetch handler, so
|
* subscriptions here - without this, subscribing to or unsubscribing
|
||||||
* apply the subscriptions there rather than on the wrapping client -
|
* from a labeler would not affect server-attached labels until the
|
||||||
* setting them on both would emit the header twice.
|
* session bundle was rebuilt.
|
||||||
|
*
|
||||||
|
* `applyLabelersToClient` writes to the agent, which is what stamps the
|
||||||
|
* header on the requests the wrapping appview client issues, and it
|
||||||
|
* drops the Bluesky moderation DID so the globally redacted authority is
|
||||||
|
* not also listed unredacted.
|
||||||
*/
|
*/
|
||||||
agent.configureLabelers(labelerDids)
|
applyLabelersToClient(agent, labelerDids)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* `BskyPreferences` is now the sdk's own type, so the assembled
|
* `BskyPreferences` is now the sdk's own type, so the assembled
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ jest.mock('jwt-decode', () => ({
|
|||||||
|
|
||||||
import {CHAT_PROXY_SERVICE} from '#/lib/constants'
|
import {CHAT_PROXY_SERVICE} from '#/lib/constants'
|
||||||
import {app, chat, com} from '#/lexicons'
|
import {app, chat, com} from '#/lexicons'
|
||||||
|
import {configureGlobalAppLabelers} from '../additional-moderation-authorities'
|
||||||
import {BskyAppAgent, PasswordSessionManager} from '../bridge-agent'
|
import {BskyAppAgent, PasswordSessionManager} from '../bridge-agent'
|
||||||
import {
|
import {
|
||||||
agentToAppviewClient,
|
agentToAppviewClient,
|
||||||
@@ -163,6 +164,32 @@ describe('agentToAppviewClient', () => {
|
|||||||
expect(entries).toHaveLength(1)
|
expect(entries).toHaveLength(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('does not duplicate a global app labeler set on both statics', async () => {
|
||||||
|
/*
|
||||||
|
* `configureGlobalAppLabelers` populates the agent AND the lex `Client`
|
||||||
|
* static, because clients built without a wrapped agent read only the
|
||||||
|
* latter. On this path both producers are in play for the same request, and
|
||||||
|
* neither dedupes against the other - the agent joins its list with the
|
||||||
|
* existing header string while lex collects into a `Set` keyed on the
|
||||||
|
* `;redact`-suffixed value. The appview client suppresses its `appLabelers`
|
||||||
|
* so exactly one producer contributes.
|
||||||
|
*/
|
||||||
|
configureGlobalAppLabelers(['did:plc:global-labeler'])
|
||||||
|
const {agent} = setup(fetchMock)
|
||||||
|
|
||||||
|
await agentToAppviewClient(agent).call(app.bsky.actor.getProfile, {
|
||||||
|
actor: HANDLE,
|
||||||
|
})
|
||||||
|
|
||||||
|
const init = initFor(fetchMock, 'app.bsky.actor.getProfile')
|
||||||
|
const labelers = new Headers(init?.headers).get('atproto-accept-labelers')
|
||||||
|
const entries = labelers!
|
||||||
|
.split(',')
|
||||||
|
.map(l => l.trim())
|
||||||
|
.filter(l => l.includes('did:plc:global-labeler'))
|
||||||
|
expect(entries).toEqual(['did:plc:global-labeler;redact'])
|
||||||
|
})
|
||||||
|
|
||||||
it('sends the session access token', async () => {
|
it('sends the session access token', async () => {
|
||||||
const {agent} = setup(fetchMock)
|
const {agent} = setup(fetchMock)
|
||||||
|
|
||||||
@@ -238,6 +265,8 @@ describe('agentToPdsClient', () => {
|
|||||||
const {agent} = setup(fetchMock)
|
const {agent} = setup(fetchMock)
|
||||||
agent.configureProxy('did:web:api.bsky.app#bsky_appview')
|
agent.configureProxy('did:web:api.bsky.app#bsky_appview')
|
||||||
agent.configureLabelersHeader(['did:plc:labeler'])
|
agent.configureLabelersHeader(['did:plc:labeler'])
|
||||||
|
/* nor the global authorities: a PDS call is not an appview read */
|
||||||
|
configureGlobalAppLabelers(['did:plc:global-labeler'])
|
||||||
|
|
||||||
await agentToPdsClient(agent).call(com.atproto.server.getSession, {})
|
await agentToPdsClient(agent).call(com.atproto.server.getSession, {})
|
||||||
|
|
||||||
@@ -302,6 +331,8 @@ describe('agentToChatClient', () => {
|
|||||||
it('does not emit the agent labeler header', async () => {
|
it('does not emit the agent labeler header', async () => {
|
||||||
const {agent} = setup(fetchMock)
|
const {agent} = setup(fetchMock)
|
||||||
agent.configureLabelersHeader(['did:plc:labeler'])
|
agent.configureLabelersHeader(['did:plc:labeler'])
|
||||||
|
/* nor the global authorities: a chat call is not an appview read */
|
||||||
|
configureGlobalAppLabelers(['did:plc:global-labeler'])
|
||||||
|
|
||||||
await agentToChatClient(agent)
|
await agentToChatClient(agent)
|
||||||
.call(chat.bsky.convo.listConvos, {})
|
.call(chat.bsky.convo.listConvos, {})
|
||||||
|
|||||||
@@ -838,8 +838,8 @@ describe('factory account snapshot after preparation', () => {
|
|||||||
*/
|
*/
|
||||||
let capturedAgent: BskyAppAgent | undefined
|
let capturedAgent: BskyAppAgent | undefined
|
||||||
mockConfigureModerationForAccount.mockImplementationOnce(
|
mockConfigureModerationForAccount.mockImplementationOnce(
|
||||||
(agent: unknown) => {
|
(bundle: unknown) => {
|
||||||
capturedAgent = agent as BskyAppAgent
|
capturedAgent = (bundle as {agent: BskyAppAgent}).agent
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
mockPrefetchAgeAssuranceServerData.mockImplementationOnce(async () => {
|
mockPrefetchAgeAssuranceServerData.mockImplementationOnce(async () => {
|
||||||
@@ -904,8 +904,8 @@ describe('a session destroyed or rejected during preparation', () => {
|
|||||||
*/
|
*/
|
||||||
let capturedAgent: BskyAppAgent | undefined
|
let capturedAgent: BskyAppAgent | undefined
|
||||||
mockConfigureModerationForAccount.mockImplementationOnce(
|
mockConfigureModerationForAccount.mockImplementationOnce(
|
||||||
(agent: unknown) => {
|
(bundle: unknown) => {
|
||||||
capturedAgent = agent as BskyAppAgent
|
capturedAgent = (bundle as {agent: BskyAppAgent}).agent
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
mockPrefetchAgeAssuranceServerData.mockImplementationOnce(async () => {
|
mockPrefetchAgeAssuranceServerData.mockImplementationOnce(async () => {
|
||||||
@@ -934,8 +934,8 @@ describe('a session destroyed or rejected during preparation', () => {
|
|||||||
it('resume: a prep rejection propagates and disposes the bundle', async () => {
|
it('resume: a prep rejection propagates and disposes the bundle', async () => {
|
||||||
let capturedAgent: BskyAppAgent | undefined
|
let capturedAgent: BskyAppAgent | undefined
|
||||||
mockConfigureModerationForAccount.mockImplementationOnce(
|
mockConfigureModerationForAccount.mockImplementationOnce(
|
||||||
(agent: unknown) => {
|
(bundle: unknown) => {
|
||||||
capturedAgent = agent as BskyAppAgent
|
capturedAgent = (bundle as {agent: BskyAppAgent}).agent
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
mockPrefetchAgeAssuranceServerData.mockImplementationOnce(() =>
|
mockPrefetchAgeAssuranceServerData.mockImplementationOnce(() =>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import {AtpAgent} from '@atproto/api'
|
import {AtpAgent} from '@atproto/api'
|
||||||
|
import {Client} from '@atproto/lex'
|
||||||
|
|
||||||
import {device} from '#/storage'
|
import {device} from '#/storage'
|
||||||
|
|
||||||
@@ -86,5 +87,23 @@ export function configureAdditionalModerationAuthorities() {
|
|||||||
new Set([...AtpAgent.appLabelers, ...additionalLabelers]),
|
new Set([...AtpAgent.appLabelers, ...additionalLabelers]),
|
||||||
)
|
)
|
||||||
|
|
||||||
AtpAgent.configure({appLabelers})
|
configureGlobalAppLabelers(appLabelers)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the global app labelers on BOTH statics, so the agent-backed request path
|
||||||
|
* and any client built without a wrapped agent emit the same `;redact`
|
||||||
|
* authorities.
|
||||||
|
*
|
||||||
|
* Keeping the two in lockstep is what makes the duplicate-header hazard
|
||||||
|
* avoidable: the agent joins its own list with whatever the caller already put
|
||||||
|
* on the request, and lex appends the `Client` static on top of that, so a DID
|
||||||
|
* present in both would appear twice. The agent-wrapping clients therefore
|
||||||
|
* suppress their `appLabelers` (see `clients.ts`), which leaves exactly one
|
||||||
|
* producer per request while both statics stay populated for the paths that
|
||||||
|
* read only one of them.
|
||||||
|
*/
|
||||||
|
export function configureGlobalAppLabelers(dids: string[]) {
|
||||||
|
AtpAgent.configure({appLabelers: dids})
|
||||||
|
Client.configure({appLabelers: dids as `did:${string}:${string}`[]})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,18 +31,30 @@ const chatClients = new WeakMap<BskyAppAgent, Client>()
|
|||||||
* routing. Because the agent already emits both headers, the client is
|
* routing. Because the agent already emits both headers, the client is
|
||||||
* deliberately built with neither a `service` option nor labelers - setting
|
* deliberately built with neither a `service` option nor labelers - setting
|
||||||
* either here would emit them a second time.
|
* either here would emit them a second time.
|
||||||
|
*
|
||||||
|
* `appLabelers: null` suppresses the class-wide `Client.appLabelers` for this
|
||||||
|
* instance specifically. The static is populated (see
|
||||||
|
* `configureGlobalAppLabelers`) so that clients built without a wrapped agent
|
||||||
|
* carry the global authorities, but the agent already stamped those same DIDs
|
||||||
|
* onto the request, and lex would append its own copy on top: the agent joins
|
||||||
|
* its list with the existing header value while lex collects into a `Set` keyed
|
||||||
|
* on the suffixed string, so neither dedupes against the other and every global
|
||||||
|
* authority would appear twice.
|
||||||
*/
|
*/
|
||||||
export function agentToAppviewClient(agent: BskyAppAgent): Client {
|
export function agentToAppviewClient(agent: BskyAppAgent): Client {
|
||||||
const existing = appviewClients.get(agent)
|
const existing = appviewClients.get(agent)
|
||||||
if (existing) {
|
if (existing) {
|
||||||
return existing
|
return existing
|
||||||
}
|
}
|
||||||
const client = createLexClient({
|
const client = createLexClient(
|
||||||
|
{
|
||||||
get did() {
|
get did() {
|
||||||
return agent.did
|
return agent.did
|
||||||
},
|
},
|
||||||
fetchHandler: (path, init) => agent.fetchHandler(path, init),
|
fetchHandler: (path, init) => agent.fetchHandler(path, init),
|
||||||
})
|
},
|
||||||
|
{appLabelers: null},
|
||||||
|
)
|
||||||
appviewClients.set(agent, client)
|
appviewClients.set(agent, client)
|
||||||
return client
|
return client
|
||||||
}
|
}
|
||||||
@@ -58,7 +70,10 @@ export function agentToAppviewClient(agent: BskyAppAgent): Client {
|
|||||||
* for `com.atproto.*` repo/server/identity calls.
|
* for `com.atproto.*` repo/server/identity calls.
|
||||||
*
|
*
|
||||||
* No `service` option for the same reason: adding one would reintroduce the
|
* No `service` option for the same reason: adding one would reintroduce the
|
||||||
* proxy header this client exists to avoid.
|
* proxy header this client exists to avoid. `appLabelers: null` is the same
|
||||||
|
* kind of suppression: a PDS request is not an appview read, so it must carry no
|
||||||
|
* moderation authorities at all - without this it would start emitting the
|
||||||
|
* global `Client.appLabelers`.
|
||||||
*
|
*
|
||||||
* The handler is wrapped in a closure rather than passed by reference because
|
* The handler is wrapped in a closure rather than passed by reference because
|
||||||
* `PasswordSessionManager.fetchHandler` reads `this`. Relative paths are
|
* `PasswordSessionManager.fetchHandler` reads `this`. Relative paths are
|
||||||
@@ -71,12 +86,16 @@ export function agentToPdsClient(agent: BskyAppAgent): Client {
|
|||||||
if (existing) {
|
if (existing) {
|
||||||
return existing
|
return existing
|
||||||
}
|
}
|
||||||
const client = createLexClient({
|
const client = createLexClient(
|
||||||
|
{
|
||||||
get did() {
|
get did() {
|
||||||
return agent.did
|
return agent.did
|
||||||
},
|
},
|
||||||
fetchHandler: (path, init) => agent.sessionManager.fetchHandler(path, init),
|
fetchHandler: (path, init) =>
|
||||||
})
|
agent.sessionManager.fetchHandler(path, init),
|
||||||
|
},
|
||||||
|
{appLabelers: null},
|
||||||
|
)
|
||||||
pdsClients.set(agent, client)
|
pdsClients.set(agent, client)
|
||||||
return client
|
return client
|
||||||
}
|
}
|
||||||
@@ -88,7 +107,8 @@ export function agentToPdsClient(agent: BskyAppAgent): Client {
|
|||||||
* and PDS routing, no agent-level proxy or labeler headers - but constructed
|
* and PDS routing, no agent-level proxy or labeler headers - but constructed
|
||||||
* with {@link CHAT_PROXY_SERVICE} as its `service`, so lex-client emits
|
* with {@link CHAT_PROXY_SERVICE} as its `service`, so lex-client emits
|
||||||
* `atproto-proxy: <CHAT_PROXY_SERVICE>` on every request and `chat.bsky.*`
|
* `atproto-proxy: <CHAT_PROXY_SERVICE>` on every request and `chat.bsky.*`
|
||||||
* calls are proxied to the chat service.
|
* calls are proxied to the chat service. `appLabelers: null` for the same
|
||||||
|
* reason as the PDS client: the chat service takes no moderation authorities.
|
||||||
*/
|
*/
|
||||||
export function agentToChatClient(agent: BskyAppAgent): Client {
|
export function agentToChatClient(agent: BskyAppAgent): Client {
|
||||||
const existing = chatClients.get(agent)
|
const existing = chatClients.get(agent)
|
||||||
@@ -103,7 +123,7 @@ export function agentToChatClient(agent: BskyAppAgent): Client {
|
|||||||
fetchHandler: (path, init) =>
|
fetchHandler: (path, init) =>
|
||||||
agent.sessionManager.fetchHandler(path, init),
|
agent.sessionManager.fetchHandler(path, init),
|
||||||
},
|
},
|
||||||
{service: CHAT_PROXY_SERVICE},
|
{appLabelers: null, service: CHAT_PROXY_SERVICE},
|
||||||
)
|
)
|
||||||
chatClients.set(agent, client)
|
chatClients.set(agent, client)
|
||||||
return client
|
return client
|
||||||
@@ -150,12 +170,14 @@ let publicLexClient: Client | undefined
|
|||||||
* {@link networkAwareFetch} so public reads feed the app's reachability signal
|
* {@link networkAwareFetch} so public reads feed the app's reachability signal
|
||||||
* like authenticated ones do.
|
* like authenticated ones do.
|
||||||
*
|
*
|
||||||
* Unlike the public agent it parallels, this client sends neither
|
* Unlike the agent-wrapping clients, this one does NOT suppress
|
||||||
* `atproto-proxy` nor `atproto-accept-labelers`. `createPublicAgent` configures
|
* `Client.appLabelers`: there is no agent underneath to stamp the header, so the
|
||||||
* the app labeler and the proxy header, so a logged-out appview *agent* read
|
* class-wide static is the only producer and a logged-out read carries the same
|
||||||
* does carry labelers while the same read through this client does not. A
|
* `;redact` moderation authorities an authenticated one does.
|
||||||
* consumer that needs moderation labels on public reads must configure labelers
|
*
|
||||||
* itself before issuing the request.
|
* That makes `configureModerationForGuest()` load-bearing rather than
|
||||||
|
* test-only - it is what populates the static before this client's first
|
||||||
|
* request. `createPublicSessionBundle` runs it while building the bundle.
|
||||||
*/
|
*/
|
||||||
export function getPublicAppviewClient(): Client {
|
export function getPublicAppviewClient(): Client {
|
||||||
return (publicLexClient ??= createLexClient({
|
return (publicLexClient ??= createLexClient({
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export async function createSessionBundleAndCreateAccount(
|
|||||||
accountDid = earlyAccount.did
|
accountDid = earlyAccount.did
|
||||||
|
|
||||||
const gates = features.refresh({strategy: 'prefer-fresh-gates'})
|
const gates = features.refresh({strategy: 'prefer-fresh-gates'})
|
||||||
configureModerationForAccount(bundle.agent, earlyAccount)
|
configureModerationForAccount(bundle, earlyAccount)
|
||||||
|
|
||||||
const createdAt = toDatetimeString(new Date())
|
const createdAt = toDatetimeString(new Date())
|
||||||
const birthdate = birthDate.toISOString()
|
const birthdate = birthDate.toISOString()
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
import {AtpAgent, BSKY_LABELER_DID} from '@atproto/api'
|
import {type AtpAgent, BSKY_LABELER_DID} from '@atproto/api'
|
||||||
|
import {type Client} from '@atproto/lex'
|
||||||
|
|
||||||
import {IS_TEST_USER} from '#/lib/constants'
|
import {IS_TEST_USER} from '#/lib/constants'
|
||||||
import {account as accountStorage} from '#/storage'
|
import {account as accountStorage} from '#/storage'
|
||||||
import {configureAdditionalModerationAuthorities} from './additional-moderation-authorities'
|
import {
|
||||||
|
configureAdditionalModerationAuthorities,
|
||||||
|
configureGlobalAppLabelers,
|
||||||
|
} from './additional-moderation-authorities'
|
||||||
import {type SessionAccount} from './types'
|
import {type SessionAccount} from './types'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,6 +30,29 @@ export function readLabelers(did: string): string[] | undefined {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply an account's labeler subscriptions without duplicating the globally
|
||||||
|
* redacted Bluesky moderation authority.
|
||||||
|
*
|
||||||
|
* The Bluesky DID is filtered out because it already flows through the global
|
||||||
|
* `appLabelers`, which lex and the agent both emit with a `;redact` suffix.
|
||||||
|
* Listing it per-subscription would add a second, non-redacting entry for the
|
||||||
|
* same authority.
|
||||||
|
*
|
||||||
|
* Writes to the agent rather than the client: the agent-level fetch handler is
|
||||||
|
* what stamps `atproto-accept-labelers` on the requests the wrapping clients
|
||||||
|
* issue, so setting them here reaches every appview read. The bundle rework
|
||||||
|
* moves this to `appviewClient.setLabelers` once the agent is gone.
|
||||||
|
*/
|
||||||
|
export function applyLabelersToClient(
|
||||||
|
agent: AtpAgent,
|
||||||
|
subscribedDids: string[],
|
||||||
|
) {
|
||||||
|
agent.configureLabelersHeader(
|
||||||
|
subscribedDids.filter(did => did !== BSKY_LABELER_DID),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function configureModerationForGuest() {
|
export function configureModerationForGuest() {
|
||||||
// This global mutation is *only* OK because this code is only relevant for testing.
|
// This global mutation is *only* OK because this code is only relevant for testing.
|
||||||
// Don't add any other global behavior here!
|
// Don't add any other global behavior here!
|
||||||
@@ -39,7 +66,7 @@ export function configureModerationForGuest() {
|
|||||||
* in the same tick, before any request goes out.
|
* in the same tick, before any request goes out.
|
||||||
*/
|
*/
|
||||||
export function configureModerationForAccount(
|
export function configureModerationForAccount(
|
||||||
agent: AtpAgent,
|
bundle: {agent: AtpAgent; appviewClient?: Client},
|
||||||
account: SessionAccount,
|
account: SessionAccount,
|
||||||
) {
|
) {
|
||||||
// This global mutation is *only* OK because this code is only relevant for testing.
|
// This global mutation is *only* OK because this code is only relevant for testing.
|
||||||
@@ -47,15 +74,13 @@ export function configureModerationForAccount(
|
|||||||
switchToBskyAppLabeler()
|
switchToBskyAppLabeler()
|
||||||
if (IS_TEST_USER(account.handle)) {
|
if (IS_TEST_USER(account.handle)) {
|
||||||
// Test accounts may briefly use the production authority while this resolves.
|
// Test accounts may briefly use the production authority while this resolves.
|
||||||
void trySwitchToTestAppLabeler(agent)
|
void trySwitchToTestAppLabeler(bundle.agent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The code below is actually relevant to production (and isn't global).
|
// The code below is actually relevant to production (and isn't global).
|
||||||
const labelerDids = readLabelers(account.did)
|
const labelerDids = readLabelers(account.did)
|
||||||
if (labelerDids) {
|
if (labelerDids) {
|
||||||
agent.configureLabelersHeader(
|
applyLabelersToClient(bundle.agent, labelerDids)
|
||||||
labelerDids.filter(did => did !== BSKY_LABELER_DID),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
// If there are no headers in the storage, we'll not send them on the initial requests.
|
// If there are no headers in the storage, we'll not send them on the initial requests.
|
||||||
// If we wanted to fix this, we could block on the preferences query here.
|
// If we wanted to fix this, we could block on the preferences query here.
|
||||||
@@ -65,7 +90,7 @@ export function configureModerationForAccount(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function switchToBskyAppLabeler() {
|
function switchToBskyAppLabeler() {
|
||||||
AtpAgent.configure({appLabelers: [BSKY_LABELER_DID]})
|
configureGlobalAppLabelers([BSKY_LABELER_DID])
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Resolve and install the test environment's moderation authority. */
|
/** Resolve and install the test environment's moderation authority. */
|
||||||
@@ -77,6 +102,6 @@ async function trySwitchToTestAppLabeler(agent: AtpAgent) {
|
|||||||
)?.data.did
|
)?.data.did
|
||||||
if (did) {
|
if (did) {
|
||||||
console.warn('USING TEST ENV MODERATION')
|
console.warn('USING TEST ENV MODERATION')
|
||||||
AtpAgent.configure({appLabelers: [did]})
|
configureGlobalAppLabelers([did])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,7 +191,9 @@ export type PublicSessionBundle = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Build the logged-out bundle. `createPublicAgent` installs the guest
|
* Build the logged-out bundle. `createPublicAgent` installs the guest
|
||||||
* moderation authorities as part of building the agent.
|
* moderation authorities as part of building the agent, which is what populates
|
||||||
|
* the global `Client.appLabelers` that {@link getPublicAppviewClient} relies on
|
||||||
|
* for its labeler header.
|
||||||
*/
|
*/
|
||||||
export function createPublicSessionBundle(): PublicSessionBundle {
|
export function createPublicSessionBundle(): PublicSessionBundle {
|
||||||
return {
|
return {
|
||||||
@@ -290,7 +292,7 @@ export async function createSessionBundleAndResume(
|
|||||||
storedAccount.pdsUrl,
|
storedAccount.pdsUrl,
|
||||||
) ?? storedAccount
|
) ?? storedAccount
|
||||||
|
|
||||||
configureModerationForAccount(bundle.agent, earlyAccount)
|
configureModerationForAccount(bundle, earlyAccount)
|
||||||
const aa = prefetchAgeAssuranceServerData({
|
const aa = prefetchAgeAssuranceServerData({
|
||||||
appviewClient: agentToAppviewClient(bundle.agent),
|
appviewClient: agentToAppviewClient(bundle.agent),
|
||||||
accountClient: agentToPdsClient(bundle.agent),
|
accountClient: agentToPdsClient(bundle.agent),
|
||||||
@@ -358,7 +360,7 @@ export async function createSessionBundleAndLogin(
|
|||||||
accountDid = earlyAccount.did
|
accountDid = earlyAccount.did
|
||||||
|
|
||||||
const gates = features.refresh({strategy: 'prefer-fresh-gates'})
|
const gates = features.refresh({strategy: 'prefer-fresh-gates'})
|
||||||
configureModerationForAccount(bundle.agent, earlyAccount)
|
configureModerationForAccount(bundle, earlyAccount)
|
||||||
const aa = prefetchAgeAssuranceServerData({
|
const aa = prefetchAgeAssuranceServerData({
|
||||||
appviewClient: agentToAppviewClient(bundle.agent),
|
appviewClient: agentToAppviewClient(bundle.agent),
|
||||||
accountClient: agentToPdsClient(bundle.agent),
|
accountClient: agentToPdsClient(bundle.agent),
|
||||||
@@ -400,7 +402,7 @@ export function createSessionBundleFromStoredAccount(
|
|||||||
)
|
)
|
||||||
bundle = buildBundle(session, storedAccount.pdsUrl)
|
bundle = buildBundle(session, storedAccount.pdsUrl)
|
||||||
registerBundleKillSwitch(bundle, hooks.kill)
|
registerBundleKillSwitch(bundle, hooks.kill)
|
||||||
configureModerationForAccount(bundle.agent, storedAccount)
|
configureModerationForAccount(bundle, storedAccount)
|
||||||
bundle.agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
bundle.agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||||
|
|
||||||
const account = session.destroyed
|
const account = session.destroyed
|
||||||
|
|||||||
Reference in New Issue
Block a user