feed-generatorを読む
/icons/hr.icon
Readme
概要
Bluesky PDSへのフィードジェネレーター(タイムライン製造機)である
ざっくりいうと、staging.bsky.appのWhat's hotを作るためのもの
ATProtocolでいうところの「カスタムアルゴリズム」を提供するための方法がFeed Generator
まだWIPで、現状は開発者向けのスターターキット
PDSがユーザーから特定フィードを閲覧したい旨のリクエスト(at-uri)を受けて、Feed Generator Serviceにリクエストを送信、Feed Generator ServiceはPOST URIを返却する Feed Generator Serviceのエンドポイントは、アルゴリズムを作成したrepoのレコードに含まれている
例えば、Bluesky公式が提供するフィードは@bsky.appのrepoで宣言される
repo内ではat-uri形式でエンドポイントが定義される
カスタムアルゴリズムを利用するフロー
1. ユーザーがPDSにat-uriで定義されるFeedを要求する
2. PDSはat-uriを名前解決する(Feed GeneratorのDIDデータからエンドポイントを取得する)
3. PDSはFeed GeneratorのエンドポイントにgetFeedSkeletonのリクエストを発行する
このリクエストはユーザーのrepo signing keyによって署名されたJWTによって(plc.directoryを経由して)認証される
4. Feed GeneratorはFeedのSkeleton(POST URIs)をPDSに返却する
5. PDSは受け取ったPOST URIsを元にFeedを構築する
将来的には、この部分はAppViewが担当することになる。現状はPDSが行う
6. PDSがユーザーにFeedを返す
ユーザーはページ切り替え(タイムライン切り替え)のような感じでこの機能を利用する。
特定フィード(特定カスタムアルゴリズム)を購読してホームに表示するようなこともできそう
Getting Started
1. indexingロジックを src/subscription.tsに実装する
2. FeedGenerationロジックを src/feed-generation.tsに実装する
このとき、 SkeletonFeedPost[]の型でreturnする必要がある
サンプルとしてテレビ番組「ALF」に関する投稿を返すフィードアルゴリズムの「whats alf」が実装されています
FeedGeneratorServiceはdid:webで定義されるが、FeedGeneratorを長期的に運用し、ドメイン移行する可能性がある場合はdid:plcに変えることも可能
Running The Server
yarnを使う。 yarn startでサーバーを起動する。ポートは3000もしくは .envで定義する。
「whats alf」フィードを見るなら下記にリクエストする
http://localhost:3000/xrpc/app.bsky.feed.getFeedSkeleton?feed=at://did:example:alice/app.bsky.feed.generator/whats-alf
その他
Skeletonの中身
code:test.ts
[
{post: 'at://did:example:1234/app.bsky.feed.post/1'},
{post: 'at://did:example:1234/app.bsky.feed.post/2'},
{post: 'at://did:example:1234/app.bsky.feed.post/3'}
]
スキーマは以下のようになっている。内容としては、
1. PDSがすべての投稿をhydratingするのを支援する。
2. 投稿をレンダリングする際に、クライアントに表示するcontextの手がかりを与える。
code:test.ts
type SkeletonItem = {
post: string // post URI
// optional reason for inclusion in the feed
// (generally to be displayed in client)
reason?: Reason
}
// for now, the only defined reason is a repost, but this is open to extension
type Reason = ReasonRepost
type ReasonRepost = {
$type: 'app.bsky.feed.defs#skeletonReasonRepost'
repost: string // repost URI
}
認証
ユーザーごとに異なる内容のfeedが表示される(ユーザーの状態が考慮される場合)は認証トークンを検証することが強く推奨される
ユーザーの認証は下記のように、repo signing keyで書面されたJWTで行われる
code:test.ts
const header = {
type: "JWT",
alg: "ES256K" // (key algorithm) - in this case secp256k1
}
const payload = {
iss: "did:example:alice", // (issuer) the requesting user's DID
aud: "did:example:feedGenerator", // (audience) the DID of the Feed Generator
exp: 1683643619 // (expiration) unix timestamp in seconds
}
JWTの検証については、 @atproto/xrpc-server の src/auth.ts にユーティリティがある
ページネーション
getFeedSkeletonメソッドはレスポンスに cursorを返し、入力としても cursorを受け取る
この curosrは timestamp + CIDで定義することを推奨
例えば、 1683654690921::bafyreia3tbsfxe3cc75xrxyyn6qc42oupi73fxiox76prlyi5bpx7hr72u
推奨される実装
getFeedSkeletonに対してどうレスポンスするかは完全にFeedGenerator側に裁量がある
ほとんどのケースでは、com.atproto.sync.subscribeReposでfirehoseを購読することを推奨
投稿を長期間保存する必要はなさそうなので、48時間より古いデータは削除してよさそう
以下事例
「What's Hot」の独自実装
firehoseから全ての投稿といいねをフィルタリングし、indexingする。投稿ごとのいいね数を記録しておき、PDSからフィードが要求された時にいいね数がしきい値を超えた最新の投稿を返す
コミュニティフィード
DIDのリストに基づいてfirehoseをフィルタリングし、リスト内のユーザーの投稿を表示する
特定のトピックに関連したフィード
firehoseから特定のトピックに関連するものをフィルタリングする
/icons/hr.icon