mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
at schema-errors 144 lines 3.6 kB view raw
1import { 2 AppBskyFeedDefs, 3 AppBskyFeedGetFeed as GetCustomFeed, 4 AtpAgent, 5 BskyAgent, 6} from '@atproto/api' 7 8import {getContentLanguages} from '#/state/preferences/languages' 9import {FeedAPI, FeedAPIResponse} from './types' 10import {createBskyTopicsHeader, isBlueskyOwnedFeed} from './utils' 11 12export class CustomFeedAPI implements FeedAPI { 13 agent: BskyAgent 14 params: GetCustomFeed.QueryParams 15 userInterests?: string 16 17 constructor({ 18 agent, 19 feedParams, 20 userInterests, 21 }: { 22 agent: BskyAgent 23 feedParams: GetCustomFeed.QueryParams 24 userInterests?: string 25 }) { 26 this.agent = agent 27 this.params = feedParams 28 this.userInterests = userInterests 29 } 30 31 async peekLatest(): Promise<AppBskyFeedDefs.FeedViewPost> { 32 const contentLangs = getContentLanguages().join(',') 33 const res = await this.agent.app.bsky.feed.getFeed( 34 { 35 ...this.params, 36 limit: 1, 37 }, 38 {headers: {'Accept-Language': contentLangs}}, 39 ) 40 return res.data.feed[0] 41 } 42 43 async fetch({ 44 cursor, 45 limit, 46 }: { 47 cursor: string | undefined 48 limit: number 49 }): Promise<FeedAPIResponse> { 50 const contentLangs = getContentLanguages().join(',') 51 const agent = this.agent 52 const isBlueskyOwned = isBlueskyOwnedFeed(this.params.feed) 53 54 const res = agent.session 55 ? await this.agent.app.bsky.feed.getFeed( 56 { 57 ...this.params, 58 cursor, 59 limit, 60 }, 61 { 62 headers: { 63 ...(isBlueskyOwned 64 ? createBskyTopicsHeader(this.userInterests) 65 : {}), 66 'Accept-Language': contentLangs, 67 }, 68 }, 69 ) 70 : await loggedOutFetch({...this.params, cursor, limit}) 71 if (res.success) { 72 // NOTE 73 // some custom feeds fail to enforce the pagination limit 74 // so we manually truncate here 75 // -prf 76 if (res.data.feed.length > limit) { 77 res.data.feed = res.data.feed.slice(0, limit) 78 } 79 return { 80 cursor: res.data.feed.length ? res.data.cursor : undefined, 81 feed: res.data.feed, 82 } 83 } 84 return { 85 feed: [], 86 } 87 } 88} 89 90// HACK 91// we want feeds to give language-specific results immediately when a 92// logged-out user changes their language. this comes with two problems: 93// 1. not all languages have content, and 94// 2. our public caching layer isnt correctly busting against the accept-language header 95// for now we handle both of these with a manual workaround 96// -prf 97async function loggedOutFetch({ 98 feed, 99 limit, 100 cursor, 101}: { 102 feed: string 103 limit: number 104 cursor?: string 105}) { 106 let contentLangs = getContentLanguages().join(',') 107 108 // manually construct fetch call so we can add the `lang` cache-busting param 109 let res = await AtpAgent.fetch!( 110 `https://api.bsky.app/xrpc/app.bsky.feed.getFeed?feed=${feed}${ 111 cursor ? `&cursor=${cursor}` : '' 112 }&limit=${limit}&lang=${contentLangs}`, 113 'GET', 114 {'Accept-Language': contentLangs}, 115 undefined, 116 ) 117 if (res.body?.feed?.length) { 118 return { 119 success: true, 120 data: res.body, 121 } 122 } 123 124 // no data, try again with language headers removed 125 res = await AtpAgent.fetch!( 126 `https://api.bsky.app/xrpc/app.bsky.feed.getFeed?feed=${feed}${ 127 cursor ? `&cursor=${cursor}` : '' 128 }&limit=${limit}`, 129 'GET', 130 {'Accept-Language': ''}, 131 undefined, 132 ) 133 if (res.body?.feed?.length) { 134 return { 135 success: true, 136 data: res.body, 137 } 138 } 139 140 return { 141 success: false, 142 data: {feed: []}, 143 } 144}