1import { Client, simpleFetchHandler } from "@atcute/client";
2import type { AppBskyFeedDefs } from "@atcute/bluesky";
3import type { ResourceUri } from "@atcute/lexicons";
4
5import config from "@/../blog.config";
6
7const handler = simpleFetchHandler({
8 // Simply hit up the Bluesky API
9 service: "https://public.api.bsky.app"
10});
11const rpc = new Client({ handler });
12
13export type ReplyThread =
14 | AppBskyFeedDefs.ThreadViewPost
15 | AppBskyFeedDefs.BlockedPost
16 | AppBskyFeedDefs.NotFoundPost;
17
18/**
19 * Fetch the first 10 replies to a post
20 * @param cid
21 * @returns
22 */
23export async function getBskyReplies(cid: string) {
24 // uri should be in format: at://did:plc:xxx/app.bsky.feed.post/xxxxx
25 const uri: ResourceUri = `at://${config.authorDid}/app.bsky.feed.post/${cid}`;
26
27 const { ok, data } = await rpc.get("app.bsky.feed.getPostThread", {
28 params: {
29 uri,
30 depth: 6 // default
31 }
32 });
33
34 if (!ok) {
35 // Handle fetch errors as 'not found'. Could be cleaner, but works just fine.
36 console.error("Error fetching thread:", data.error);
37 return { $type: "app.bsky.feed.defs#notFoundPost" };
38 }
39
40 if (ok) {
41 return data.thread;
42 }
43
44 return { $type: "app.bsky.feed.defs#notFoundPost" };
45}
46
47/**
48 * Extract post id from an atproto uri
49 * @param uri The atproto uri, such as at://did:plc:user/app.bsky.feed.post/xxxxx`
50 * @returns The post id
51 */
52export function extractPostId(uri: ResourceUri) {
53 if (uri.includes("app.bsky.feed.post")) {
54 const parts = uri.split("/");
55 return parts.at(-1);
56 }
57 return "";
58}