rework session layer on PasswordSession + three-client pattern
- PasswordSession (@atproto/lex-password-session) is now the single auth
core; SessionAgent bridges it to the base Agent from @atproto/api so
the ~148 useAgent() consumer files keep working unchanged
- SessionBundle carries {session, agent, accountClient, appviewClient};
useLexClient() now returns the authed appview client, new
useAppviewClient()/usePdsClient() hooks
- reducer: OpaqueSessionBundle, new replaced-current-bundle action for
network-free cross-tab same-did sync (PasswordSession is immutable, so
the bundle is rebuilt instead of mutated in place)
- moderation: AtpAgent.configure -> Client.configure + Agent.configure,
per-account labelers on both the bridge and the appview client
- push-token unregistration uses temporary PasswordSessions
- hard-tail migrations: SignupQueued refresh via resumeSession shim,
useBeginAgeAssurance scoped-token raw Client, useAccountEmailState
reads currentAccount
- PDS routing preserved on the no-network resume fast path by
synthesizing a minimal didDoc from the persisted pdsUrl
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
import {type AtpAgent} from '@atproto/api'
|
||||
import {Client} from '@atproto/lex-client'
|
||||
import {type PasswordSession} from '@atproto/lex-password-session'
|
||||
import {api} from '@bsky.app/sdk'
|
||||
|
||||
import {PUBLIC_BSKY_SERVICE} from '#/lib/constants'
|
||||
import {networkAwareFetch} from './session-core'
|
||||
|
||||
/**
|
||||
* Stable per-agent cache of lex `Client` instances. We never reuse an
|
||||
@@ -58,11 +61,55 @@ export function agentToLexClient(agent: AtpAgent): Client {
|
||||
*/
|
||||
let publicClient: Client | undefined
|
||||
|
||||
function getPublicLexClient(): Client {
|
||||
publicClient ??= new Client(PUBLIC_BSKY_SERVICE)
|
||||
export function getPublicLexClient(): Client {
|
||||
/*
|
||||
* Pass networkAwareFetch so the unauthenticated public path feeds the same
|
||||
* reachability signal as the session-backed clients (see session-core).
|
||||
*/
|
||||
publicClient ??= new Client({
|
||||
service: PUBLIC_BSKY_SERVICE,
|
||||
fetch: networkAwareFetch,
|
||||
})
|
||||
return publicClient
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the account (PDS) client over a {@link PasswordSession}. Writes and
|
||||
* record mutations go here - no `atproto-proxy` header, so requests hit the
|
||||
* user's PDS directly (the session's `fetchHandler` resolves the PDS origin
|
||||
* per request from the didDoc, falling back to `service`).
|
||||
*
|
||||
* The session already owns its own `fetch` (networkAwareFetch, set at
|
||||
* construction), so we intentionally do NOT pass `fetch` here: a `Client`
|
||||
* built over an existing `Agent`/session uses that agent's fetch.
|
||||
*/
|
||||
export function buildAccountClient(session: PasswordSession): Client {
|
||||
return new Client(session)
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the authed appview client over a {@link PasswordSession}.
|
||||
*
|
||||
* Requests are proxied to the Bluesky appview (`atproto-proxy:
|
||||
* did:web:api.bsky.app#bsky_appview`) and carry the per-instance labelers.
|
||||
* The Bluesky moderation labeler (`api.moderation.did`) is always included as
|
||||
* a base labeler because sending ANY `atproto-accept-labelers` header replaces
|
||||
* the server-side default - so we must re-assert it to keep it active.
|
||||
*/
|
||||
export function buildAppviewClient(
|
||||
session: PasswordSession,
|
||||
labelerDids: string[],
|
||||
): Client {
|
||||
return new Client(session, {
|
||||
service: api.app.service,
|
||||
/* labelerDids are validated DID strings; cast to the DidString template type */
|
||||
labelers: [
|
||||
api.moderation.did,
|
||||
...labelerDids,
|
||||
] as `did:${string}:${string}`[],
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Unauthenticated lex {@link Client} for public appview reads. A process-wide
|
||||
* singleton, so its identity is stable across renders.
|
||||
|
||||
Reference in New Issue
Block a user