/** * @copyright nhcarrigan * @license Naomi's Public License * @author Naomi Carrigan */ import { AtpAgent } from "@atproto/api"; /** * Forwards an announcement to our Bluesky account. * @param content - The main body of the announcement. * @returns A message indicating the success or failure of the operation. */ // eslint-disable-next-line max-lines-per-function, max-statements -- This is a big function. export const announceOnBluesky = async( content: Array, ): Promise => { if (process.env.BSKY_APP_PASSWORD === undefined) { return "Bluesky credentials are not set."; } const [ firstPost, ...restOfPosts ] = content; const failedReplies: Array = []; if (firstPost === undefined) { return "No posts to send to Bluesky."; } const agent = new AtpAgent({ service: "https://bsky.social", }); await agent.login({ identifier: "nhcarrigan.com", password: process.env.BSKY_APP_PASSWORD, }); const blueskyRequest = await agent.post({ text: firstPost, }).catch((error: unknown) => { return error instanceof Error ? error.message : String(error); }); if (typeof blueskyRequest === "string") { return `Failed to send initial post to Bluesky. ${blueskyRequest}`; } const rootUri = blueskyRequest.uri; const rootCid = blueskyRequest.cid; let parentUri = rootUri; let parentCid = rootCid; for (const post of restOfPosts) { // eslint-disable-next-line no-await-in-loop -- We need to do this sequentially. const blueskyResponse = await agent.post({ reply: { parent: { cid: parentCid, uri: parentUri, }, root: { cid: rootCid, uri: rootUri, }, }, text: post, }).catch((error: unknown) => { return error instanceof Error ? error.message : String(error); }); if (typeof blueskyResponse === "string") { failedReplies.push(post); continue; } parentUri = blueskyResponse.uri; parentCid = blueskyResponse.cid; } return `Successfully sent initial post to Bluesky. ${failedReplies.length > 0 ? `Failed to send ${failedReplies.length.toString()} replies: ${failedReplies.join(", ")}` : `All ${(content.length - 1).toString()} replies were sent successfully.`}`; };