pleroma-like client for Bluesky
pl.hexmani.ac
bluesky
pleroma
social-media
1import { Client } from "@atcute/client";
2import { agent } from "../components/login";
3import { FeedViewPost } from "@atcute/bluesky/types/app/feed/defs";
4import type { Post } from "../types/post";
5import { is } from "@atcute/lexicons";
6import { AppBskyFeedPost } from "@atcute/bluesky";
7
8export async function getFollowingTimeline(
9 cursor: string = "",
10 limit: number = 50,
11) {
12 const rpc = new Client({ handler: agent });
13
14 const res = await rpc.get("app.bsky.feed.getTimeline", {
15 params: {
16 cursor,
17 limit,
18 },
19 });
20
21 if (!res.ok) {
22 throw new Error(
23 `Failed to fetch user's following timeline: ${res.data.error}/${res.data.message}`,
24 );
25 }
26
27 return { feed: res.data.feed, cursor: res.data.cursor };
28}
29
30export async function createPostElements(feed: FeedViewPost[]) {
31 let elms: Post[] = [];
32 const seenCreators = new Set<string>();
33
34 feed.forEach((post) => {
35 if (is(AppBskyFeedPost.mainSchema, post.post.record)) {
36 const record = post.post.record as unknown as AppBskyFeedPost.Main;
37 const isReply = record.reply !== undefined;
38 const creatorDid = post.post.author.did;
39
40 // Skip replies from creators who already have a post in elms
41 if (isReply && seenCreators.has(creatorDid)) {
42 return;
43 }
44
45 if (post.reason) {
46 if (post.reason.$type === "app.bsky.feed.defs#reasonRepost") {
47 elms.push({
48 avatar: post.post.author.avatar,
49 context: {
50 invoker: post.reason.by,
51 reason: post.reason.$type,
52 },
53 counts: {
54 bookmarkCount: post.post.bookmarkCount,
55 likeCount: post.post.likeCount,
56 quoteCount: post.post.quoteCount,
57 repostCount: post.post.repostCount,
58 replyCount: post.post.replyCount,
59 },
60 createdAt: new Date(post.post.record.createdAt),
61 displayName:
62 post.post.author.displayName || post.post.author.handle,
63 handle: post.post.author.handle,
64 indexedAt: new Date(post.post.indexedAt),
65 record: record,
66 });
67 seenCreators.add(creatorDid);
68 }
69 } else {
70 elms.push({
71 avatar: post.post.author.avatar,
72 counts: {
73 bookmarkCount: post.post.bookmarkCount,
74 likeCount: post.post.likeCount,
75 quoteCount: post.post.quoteCount,
76 repostCount: post.post.repostCount,
77 replyCount: post.post.replyCount,
78 },
79 createdAt: new Date(post.post.record.createdAt),
80 displayName: post.post.author.displayName || post.post.author.handle,
81 handle: post.post.author.handle,
82 indexedAt: new Date(post.post.indexedAt),
83 record: record,
84 });
85 seenCreators.add(creatorDid);
86 }
87 }
88 });
89
90 return elms;
91}