a tool for shared writing and social publishing
1import { inngest } from "../client";
2import { supabaseServerClient } from "supabase/serverClient";
3import { AtpAgent, AtUri } from "@atproto/api";
4import { idResolver } from "app/(home-pages)/reader/idResolver";
5
6const TOTAL_ITERATIONS = 144; // 36 hours at 15-minute intervals
7
8export const sync_document_metadata = inngest.createFunction(
9 {
10 id: "sync_document_metadata",
11 idempotency: "event.data.document_uri",
12 },
13 { event: "appview/sync-document-metadata" },
14 async ({ event, step }) => {
15 const { document_uri, bsky_post_uri } = event.data;
16
17 const did = new AtUri(document_uri).host;
18
19 const handleResult = await step.run("resolve-handle", async () => {
20 const doc = await idResolver.did.resolve(did);
21 const handle = doc?.alsoKnownAs
22 ?.find((a) => a.startsWith("at://"))
23 ?.replace("at://", "");
24 return { handle: handle ?? null, isBridgy: handle?.includes("brid.gy") ?? false };
25 });
26
27 if (handleResult.isBridgy) {
28 await step.run("set-unindexed", async () => {
29 await supabaseServerClient
30 .from("documents")
31 .update({ indexed: false })
32 .eq("uri", document_uri);
33 });
34 }
35
36 if (!bsky_post_uri || handleResult.isBridgy) {
37 return { handle: handleResult.handle };
38 }
39
40 const agent = new AtpAgent({ service: "https://public.api.bsky.app" });
41
42 const fetchAndUpdate = async () => {
43 const res = await agent.app.bsky.feed.getPosts({
44 uris: [bsky_post_uri],
45 });
46 const post = res.data.posts[0];
47 if (!post) return 0;
48 const likeCount = post.likeCount ?? 0;
49 await supabaseServerClient
50 .from("documents")
51 .update({ bsky_like_count: likeCount })
52 .eq("uri", document_uri);
53 return likeCount;
54 };
55
56 let likeCount = await step.run("sync-0", fetchAndUpdate);
57
58 for (let i = 1; i < TOTAL_ITERATIONS; i++) {
59 await step.sleep(`wait-${i}`, "15m");
60 likeCount = await step.run(`sync-${i}`, fetchAndUpdate);
61 }
62
63 return { likeCount, handle: handleResult.handle };
64 },
65);