From 623d3699e954017c650b44c8df254132c0381201 Mon Sep 17 00:00:00 2001 From: Furkan Emin Can <78358128+femincan@users.noreply.github.com> Date: Mon, 20 Apr 2026 14:45:29 +0300 Subject: [PATCH] feat: add Bluesky data provider for url-metadata --- .../url-metadata/data-providers/bluesky.ts | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 apps/worker/src/tasks/url-metadata/data-providers/bluesky.ts diff --git a/apps/worker/src/tasks/url-metadata/data-providers/bluesky.ts b/apps/worker/src/tasks/url-metadata/data-providers/bluesky.ts new file mode 100644 index 00000000..a4651e87 --- /dev/null +++ b/apps/worker/src/tasks/url-metadata/data-providers/bluesky.ts @@ -0,0 +1,59 @@ +import { fetchAsBot } from "../../../utils/fetchAsBot.ts"; + +interface BlueskyAPIResponse { + posts: { + author: { + handle: string; + displayName: string; + avatar: string; + }; + record: { + createdAt: string; + text: string; + }; + replyCount: number; + repostCount: number; + likeCount: number; + }[]; +} + +export interface GetBlueskyPostDataProps { + userHandle: string; + postId: string; + signal: AbortSignal; +} + +export async function getBlueskyPostData({ + userHandle, + postId, + signal, +}: GetBlueskyPostDataProps) { + const baseUrl = "https://public.api.bsky.app/xrpc"; + + const didRes = await fetchAsBot({ + url: `${baseUrl}/com.atproto.identity.resolveHandle?handle=${userHandle}`, + method: "GET", + skipRobotsCheck: true, + signal, + }); + const didData = (await didRes.body.json()) as { did: string }; + const did = didData.did; + const uri = `at://${did}/app.bsky.feed.post/${postId}`; + + const res = await fetchAsBot({ + url: `${baseUrl}/app.bsky.feed.getPosts?uris=${encodeURIComponent(uri)}`, + method: "GET", + skipRobotsCheck: true, + signal, + }); + const json = (await res.body.json()) as BlueskyAPIResponse; + + if (!json.posts?.length) { + res.body.dump(); + throw new Error( + `No post found for userHandle: ${userHandle}, postId: ${postId}`, + ); + } + + return json.posts[0]; +}