Skip to content

Commit

Permalink
add trending topic lex, wire in agent (#3250)
Browse files Browse the repository at this point in the history
* add lex

* add suggested as well

* don't use uri format

* codegen

* tweak lex

* wire in

* add missing var

* move

* make auth optional

* mount

* add trending topics to server cfg (#3226)

* add trending topics to server cfg

* rename stuff

* remove langs

* make viewer nullable

* recodegen

* changeset again

---------

Co-authored-by: dholms <[email protected]>
  • Loading branch information
haileyok and dholms authored Dec 16, 2024
1 parent 13636ba commit dced566
Show file tree
Hide file tree
Showing 25 changed files with 792 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/wise-toys-judge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@atproto/api": patch
---

add trending topics
10 changes: 10 additions & 0 deletions lexicons/app/bsky/unspecced/defs.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@
"properties": {
"uri": { "type": "string", "format": "at-uri" }
}
},
"trendingTopic": {
"type": "object",
"required": ["topic", "link"],
"properties": {
"topic": { "type": "string" },
"displayName": { "type": "string" },
"description": { "type": "string" },
"link": { "type": "string" }
}
}
}
}
49 changes: 49 additions & 0 deletions lexicons/app/bsky/unspecced/getTrendingTopics.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"lexicon": 1,
"id": "app.bsky.unspecced.getTrendingTopics",
"defs": {
"main": {
"type": "query",
"description": "Get a list of trending topics",
"parameters": {
"type": "params",
"properties": {
"viewer": {
"type": "string",
"format": "did",
"description": "DID of the account making the request (not included for public/unauthenticated queries). Used to boost followed accounts in ranking."
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 25,
"default": 10
}
}
},
"output": {
"encoding": "application/json",
"schema": {
"type": "object",
"required": ["topics", "suggested"],
"properties": {
"topics": {
"type": "array",
"items": {
"type": "ref",
"ref": "app.bsky.unspecced.defs#trendingTopic"
}
},
"suggested": {
"type": "array",
"items": {
"type": "ref",
"ref": "app.bsky.unspecced.defs#trendingTopic"
}
}
}
}
}
}
}
}
14 changes: 14 additions & 0 deletions packages/api/src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ import * as AppBskyUnspeccedGetConfig from './types/app/bsky/unspecced/getConfig
import * as AppBskyUnspeccedGetPopularFeedGenerators from './types/app/bsky/unspecced/getPopularFeedGenerators'
import * as AppBskyUnspeccedGetSuggestionsSkeleton from './types/app/bsky/unspecced/getSuggestionsSkeleton'
import * as AppBskyUnspeccedGetTaggedSuggestions from './types/app/bsky/unspecced/getTaggedSuggestions'
import * as AppBskyUnspeccedGetTrendingTopics from './types/app/bsky/unspecced/getTrendingTopics'
import * as AppBskyUnspeccedSearchActorsSkeleton from './types/app/bsky/unspecced/searchActorsSkeleton'
import * as AppBskyUnspeccedSearchPostsSkeleton from './types/app/bsky/unspecced/searchPostsSkeleton'
import * as AppBskyUnspeccedSearchStarterPacksSkeleton from './types/app/bsky/unspecced/searchStarterPacksSkeleton'
Expand Down Expand Up @@ -394,6 +395,7 @@ export * as AppBskyUnspeccedGetConfig from './types/app/bsky/unspecced/getConfig
export * as AppBskyUnspeccedGetPopularFeedGenerators from './types/app/bsky/unspecced/getPopularFeedGenerators'
export * as AppBskyUnspeccedGetSuggestionsSkeleton from './types/app/bsky/unspecced/getSuggestionsSkeleton'
export * as AppBskyUnspeccedGetTaggedSuggestions from './types/app/bsky/unspecced/getTaggedSuggestions'
export * as AppBskyUnspeccedGetTrendingTopics from './types/app/bsky/unspecced/getTrendingTopics'
export * as AppBskyUnspeccedSearchActorsSkeleton from './types/app/bsky/unspecced/searchActorsSkeleton'
export * as AppBskyUnspeccedSearchPostsSkeleton from './types/app/bsky/unspecced/searchPostsSkeleton'
export * as AppBskyUnspeccedSearchStarterPacksSkeleton from './types/app/bsky/unspecced/searchStarterPacksSkeleton'
Expand Down Expand Up @@ -3089,6 +3091,18 @@ export class AppBskyUnspeccedNS {
)
}

getTrendingTopics(
params?: AppBskyUnspeccedGetTrendingTopics.QueryParams,
opts?: AppBskyUnspeccedGetTrendingTopics.CallOptions,
): Promise<AppBskyUnspeccedGetTrendingTopics.Response> {
return this._client.call(
'app.bsky.unspecced.getTrendingTopics',
params,
undefined,
opts,
)
}

searchActorsSkeleton(
params?: AppBskyUnspeccedSearchActorsSkeleton.QueryParams,
opts?: AppBskyUnspeccedSearchActorsSkeleton.CallOptions,
Expand Down
69 changes: 69 additions & 0 deletions packages/api/src/client/lexicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9257,6 +9257,24 @@ export const schemaDict = {
},
},
},
trendingTopic: {
type: 'object',
required: ['topic', 'link'],
properties: {
topic: {
type: 'string',
},
displayName: {
type: 'string',
},
description: {
type: 'string',
},
link: {
type: 'string',
},
},
},
},
},
AppBskyUnspeccedGetConfig: {
Expand Down Expand Up @@ -9437,6 +9455,56 @@ export const schemaDict = {
},
},
},
AppBskyUnspeccedGetTrendingTopics: {
lexicon: 1,
id: 'app.bsky.unspecced.getTrendingTopics',
defs: {
main: {
type: 'query',
description: 'Get a list of trending topics',
parameters: {
type: 'params',
properties: {
viewer: {
type: 'string',
format: 'did',
description:
'DID of the account making the request (not included for public/unauthenticated queries). Used to boost followed accounts in ranking.',
},
limit: {
type: 'integer',
minimum: 1,
maximum: 25,
default: 10,
},
},
},
output: {
encoding: 'application/json',
schema: {
type: 'object',
required: ['topics', 'suggested'],
properties: {
topics: {
type: 'array',
items: {
type: 'ref',
ref: 'lex:app.bsky.unspecced.defs#trendingTopic',
},
},
suggested: {
type: 'array',
items: {
type: 'ref',
ref: 'lex:app.bsky.unspecced.defs#trendingTopic',
},
},
},
},
},
},
},
},
AppBskyUnspeccedSearchActorsSkeleton: {
lexicon: 1,
id: 'app.bsky.unspecced.searchActorsSkeleton',
Expand Down Expand Up @@ -13686,6 +13754,7 @@ export const ids = {
'app.bsky.unspecced.getSuggestionsSkeleton',
AppBskyUnspeccedGetTaggedSuggestions:
'app.bsky.unspecced.getTaggedSuggestions',
AppBskyUnspeccedGetTrendingTopics: 'app.bsky.unspecced.getTrendingTopics',
AppBskyUnspeccedSearchActorsSkeleton:
'app.bsky.unspecced.searchActorsSkeleton',
AppBskyUnspeccedSearchPostsSkeleton: 'app.bsky.unspecced.searchPostsSkeleton',
Expand Down
20 changes: 20 additions & 0 deletions packages/api/src/client/types/app/bsky/unspecced/defs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,23 @@ export function validateSkeletonSearchStarterPack(
v,
)
}

export interface TrendingTopic {
topic: string
displayName?: string
description?: string
link: string
[k: string]: unknown
}

export function isTrendingTopic(v: unknown): v is TrendingTopic {
return (
isObj(v) &&
hasProp(v, '$type') &&
v.$type === 'app.bsky.unspecced.defs#trendingTopic'
)
}

export function validateTrendingTopic(v: unknown): ValidationResult {
return lexicons.validate('app.bsky.unspecced.defs#trendingTopic', v)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* GENERATED CODE - DO NOT MODIFY
*/
import { HeadersMap, XRPCError } from '@atproto/xrpc'
import { ValidationResult, BlobRef } from '@atproto/lexicon'
import { isObj, hasProp } from '../../../../util'
import { lexicons } from '../../../../lexicons'
import { CID } from 'multiformats/cid'
import * as AppBskyUnspeccedDefs from './defs'

export interface QueryParams {
/** DID of the account making the request (not included for public/unauthenticated queries). Used to boost followed accounts in ranking. */
viewer?: string
limit?: number
}

export type InputSchema = undefined

export interface OutputSchema {
topics: AppBskyUnspeccedDefs.TrendingTopic[]
suggested: AppBskyUnspeccedDefs.TrendingTopic[]
[k: string]: unknown
}

export interface CallOptions {
signal?: AbortSignal
headers?: HeadersMap
}

export interface Response {
success: boolean
headers: HeadersMap
data: OutputSchema
}

export function toKnownErr(e: any) {
return e
}
1 change: 1 addition & 0 deletions packages/bsky/src/api/app/bsky/unspecced/getConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default function (server: Server, ctx: AppContext) {
encoding: 'application/json',
body: {
checkEmailConfirmed: ctx.cfg.clientCheckEmailConfirmed,
topicsEnabled: ctx.cfg.topicsEnabled,
},
}
},
Expand Down
97 changes: 97 additions & 0 deletions packages/bsky/src/api/app/bsky/unspecced/getTrendingTopics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { noUndefinedVals } from '@atproto/common'
import AppContext from '../../../../context'
import { Server } from '../../../../lexicon'
import {
createPipeline,
HydrationFnInput,
PresentationFnInput,
RulesFnInput,
SkeletonFnInput,
} from '../../../../pipeline'
import { HydrateCtx, Hydrator } from '../../../../hydration/hydrator'
import { Views } from '../../../../views'
import { QueryParams } from '../../../../lexicon/types/app/bsky/unspecced/getTrendingTopics'
import AtpAgent from '@atproto/api'
import { TrendingTopic } from '../../../../lexicon/types/app/bsky/unspecced/defs'
import { InternalServerError } from '@atproto/xrpc-server'

export default function (server: Server, ctx: AppContext) {
const getTrendingTopics = createPipeline(
skeleton,
hydration,
noBlocksOrMutes,
presentation,
)
server.app.bsky.unspecced.getTrendingTopics({
auth: ctx.authVerifier.standardOptional,
handler: async ({ auth, params, req }) => {
const viewer = auth.credentials.iss
const labelers = ctx.reqLabelers(req)
const hydrateCtx = await ctx.hydrator.createContext({ labelers, viewer })
const headers = noUndefinedVals({
'accept-language': req.headers['accept-language'],
})
const { ...result } = await getTrendingTopics(
{ ...params, hydrateCtx: hydrateCtx.copy({ viewer }), headers },
ctx,
)
return {
encoding: 'application/json',
body: result,
}
},
})
}

const skeleton = async (input: SkeletonFnInput<Context, Params>) => {
const { params, ctx } = input
if (ctx.topicsAgent) {
const res = await ctx.topicsAgent.app.bsky.unspecced.getTrendingTopics(
{
viewer: params.viewer,
},
{
headers: params.headers,
},
)
return res.data
} else {
throw new InternalServerError('Topics agent not available')
}
}

const hydration = async (
_: HydrationFnInput<Context, Params, SkeletonState>,
) => {
return {}
}

const noBlocksOrMutes = (
input: RulesFnInput<Context, Params, SkeletonState>,
) => {
const { skeleton } = input
return skeleton
}

const presentation = (
input: PresentationFnInput<Context, Params, SkeletonState>,
) => {
const { skeleton } = input
return skeleton
}

type Context = {
hydrator: Hydrator
views: Views
topicsAgent: AtpAgent | undefined
}

type Params = QueryParams & {
hydrateCtx: HydrateCtx & { viewer: string | null }
headers: Record<string, string>
}

type SkeletonState = {
topics: TrendingTopic[]
suggested: TrendingTopic[]
}
2 changes: 2 additions & 0 deletions packages/bsky/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import unmuteActorList from './app/bsky/graph/unmuteActorList'
import muteThread from './app/bsky/graph/muteThread'
import unmuteThread from './app/bsky/graph/unmuteThread'
import getSuggestedFollowsByActor from './app/bsky/graph/getSuggestedFollowsByActor'
import getTrendingTopics from './app/bsky/unspecced/getTrendingTopics'
import getLabelerServices from './app/bsky/labeler/getServices'
import searchActors from './app/bsky/actor/searchActors'
import searchActorsTypeahead from './app/bsky/actor/searchActorsTypeahead'
Expand Down Expand Up @@ -104,6 +105,7 @@ export default function (server: Server, ctx: AppContext) {
muteThread(server, ctx)
unmuteThread(server, ctx)
getSuggestedFollowsByActor(server, ctx)
getTrendingTopics(server, ctx)
getLabelerServices(server, ctx)
searchActors(server, ctx)
searchActorsTypeahead(server, ctx)
Expand Down
Loading

0 comments on commit dced566

Please sign in to comment.