migrate runtime call sites to lex clients and sdk actions
Phase 3 tasks 3-7 (parallel wave): composer/post pipeline on pdsClient/appviewClient with structural+instance blob guards and a golden CID fixture test; chat Convo/EventBus/queries on the dedicated chat client; preferences sugar to SDK actions on the PDS client; remaining state/queries producers (usePostThread unspecced flip, video scoped-token clients, notifications, starter packs, lists) to client.call; UI runtime sweep (AtUri from @atproto/syntax, moderation fns from @bsky.app/sdk/moderation, SDK RichText, ozone reason tokens, guard rewrites via #/types/bsky). Intermediate checkpoint (hooks skipped): ~114 typecheck errors remain in cross-boundary consumer files, resolved by the type-only codemod next. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+67
-52
@@ -1,47 +1,53 @@
|
||||
import {
|
||||
type AppBskyFeedDefs,
|
||||
type AppBskyFeedGetFeed as GetCustomFeed,
|
||||
AtpAgent,
|
||||
jsonStringToLex,
|
||||
} from '@atproto/api'
|
||||
import {lexParse} from '@atproto/lex'
|
||||
import {Client} from '@atproto/lex-client'
|
||||
|
||||
import {
|
||||
getAppLanguageAsContentLanguage,
|
||||
getContentLanguages,
|
||||
} from '#/state/preferences/languages'
|
||||
import {type SessionAgent} from '#/state/session'
|
||||
import {app} from '#/lexicons'
|
||||
import {type FeedAPI, type FeedAPIResponse} from './types'
|
||||
import {createBskyTopicsHeader, isBlueskyOwnedFeed} from './utils'
|
||||
|
||||
/**
|
||||
* Input params for {@link CustomFeedAPI}. The generated `$Params` type reflects
|
||||
* post-parse output, where `limit` (which has a lexicon default) is required;
|
||||
* callers supply only `feed` and let `limit`/`cursor` come from `fetch`.
|
||||
*/
|
||||
type CustomFeedParams = {feed: app.bsky.feed.getFeed.$Params['feed']} & Partial<
|
||||
Omit<app.bsky.feed.getFeed.$Params, 'feed'>
|
||||
>
|
||||
|
||||
export class CustomFeedAPI implements FeedAPI {
|
||||
agent: SessionAgent
|
||||
params: GetCustomFeed.QueryParams
|
||||
client: Client
|
||||
params: CustomFeedParams
|
||||
userInterests?: string
|
||||
|
||||
constructor({
|
||||
agent,
|
||||
client,
|
||||
feedParams,
|
||||
userInterests,
|
||||
}: {
|
||||
agent: SessionAgent
|
||||
feedParams: GetCustomFeed.QueryParams
|
||||
client: Client
|
||||
feedParams: CustomFeedParams
|
||||
userInterests?: string
|
||||
}) {
|
||||
this.agent = agent
|
||||
this.client = client
|
||||
this.params = feedParams
|
||||
this.userInterests = userInterests
|
||||
}
|
||||
|
||||
async peekLatest(): Promise<AppBskyFeedDefs.FeedViewPost> {
|
||||
async peekLatest(): Promise<app.bsky.feed.defs.FeedViewPost> {
|
||||
const contentLangs = getContentLanguages().join(',')
|
||||
const res = await this.agent.app.bsky.feed.getFeed(
|
||||
const res = await this.client.call(
|
||||
app.bsky.feed.getFeed,
|
||||
{
|
||||
...this.params,
|
||||
limit: 1,
|
||||
},
|
||||
{headers: {'Accept-Language': contentLangs}},
|
||||
)
|
||||
return res.data.feed[0]
|
||||
return res.feed[0]
|
||||
}
|
||||
|
||||
async fetch({
|
||||
@@ -52,41 +58,49 @@ export class CustomFeedAPI implements FeedAPI {
|
||||
limit: number
|
||||
}): Promise<FeedAPIResponse> {
|
||||
const contentLangs = getContentLanguages().join(',')
|
||||
const agent = this.agent
|
||||
const isBlueskyOwned = isBlueskyOwnedFeed(this.params.feed)
|
||||
|
||||
const res = agent.did
|
||||
? await this.agent.app.bsky.feed.getFeed(
|
||||
{
|
||||
...this.params,
|
||||
cursor,
|
||||
limit,
|
||||
let feed: app.bsky.feed.defs.FeedViewPost[]
|
||||
let resCursor: string | undefined
|
||||
|
||||
if (this.client.did) {
|
||||
const res = await this.client.call(
|
||||
app.bsky.feed.getFeed,
|
||||
{
|
||||
...this.params,
|
||||
cursor,
|
||||
limit,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
...(isBlueskyOwned
|
||||
? createBskyTopicsHeader(this.userInterests)
|
||||
: {}),
|
||||
'Accept-Language': contentLangs,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
...(isBlueskyOwned
|
||||
? createBskyTopicsHeader(this.userInterests)
|
||||
: {}),
|
||||
'Accept-Language': contentLangs,
|
||||
},
|
||||
},
|
||||
)
|
||||
: await loggedOutFetch({...this.params, cursor, limit})
|
||||
if (res.success) {
|
||||
// NOTE
|
||||
// some custom feeds fail to enforce the pagination limit
|
||||
// so we manually truncate here
|
||||
// -prf
|
||||
if (res.data.feed.length > limit) {
|
||||
res.data.feed = res.data.feed.slice(0, limit)
|
||||
}
|
||||
return {
|
||||
cursor: res.data.feed.length ? res.data.cursor : undefined,
|
||||
feed: res.data.feed,
|
||||
},
|
||||
)
|
||||
feed = res.feed
|
||||
resCursor = res.cursor
|
||||
} else {
|
||||
const res = await loggedOutFetch({...this.params, cursor, limit})
|
||||
if (!res.success) {
|
||||
return {feed: []}
|
||||
}
|
||||
feed = res.data.feed
|
||||
resCursor = res.data.cursor
|
||||
}
|
||||
|
||||
// NOTE
|
||||
// some custom feeds fail to enforce the pagination limit
|
||||
// so we manually truncate here
|
||||
// -prf
|
||||
if (feed.length > limit) {
|
||||
feed = feed.slice(0, limit)
|
||||
}
|
||||
return {
|
||||
feed: [],
|
||||
cursor: feed.length ? resCursor : undefined,
|
||||
feed,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,15 +120,16 @@ async function loggedOutFetch({
|
||||
feed: string
|
||||
limit: number
|
||||
cursor?: string
|
||||
}) {
|
||||
}): Promise<{success: boolean; data: app.bsky.feed.getFeed.$OutputBody}> {
|
||||
let contentLangs = getAppLanguageAsContentLanguage()
|
||||
|
||||
/**
|
||||
* Copied from our root `Agent` class
|
||||
* @see https://github.com/bluesky-social/atproto/blob/60df3fc652b00cdff71dd9235d98a7a4bb828f05/packages/api/src/agent.ts#L120
|
||||
/*
|
||||
* Copied from our root `Agent` class. The global (`;redact`-suffixed) app
|
||||
* labelers are kept on the lex `Client` static (synced in
|
||||
* `#/state/session/moderation`), replacing the old `AtpAgent.appLabelers`.
|
||||
*/
|
||||
const labelersHeader = {
|
||||
'atproto-accept-labelers': AtpAgent.appLabelers
|
||||
'atproto-accept-labelers': Client.appLabelers
|
||||
.map(l => `${l};redact`)
|
||||
.join(', '),
|
||||
}
|
||||
@@ -130,7 +145,7 @@ async function loggedOutFetch({
|
||||
},
|
||||
)
|
||||
let data = res.ok
|
||||
? (jsonStringToLex(await res.text()) as GetCustomFeed.OutputSchema)
|
||||
? (lexParse(await res.text()) as app.bsky.feed.getFeed.$OutputBody)
|
||||
: null
|
||||
if (data?.feed?.length) {
|
||||
return {
|
||||
@@ -147,7 +162,7 @@ async function loggedOutFetch({
|
||||
{method: 'GET', headers: {'Accept-Language': '', ...labelersHeader}},
|
||||
)
|
||||
data = res.ok
|
||||
? (jsonStringToLex(await res.text()) as GetCustomFeed.OutputSchema)
|
||||
? (lexParse(await res.text()) as app.bsky.feed.getFeed.$OutputBody)
|
||||
: null
|
||||
if (data?.feed?.length) {
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user