a tool for shared writing and social publishing
at update/thread-viewer 75 lines 2.1 kB view raw
1import { Agent, lexToJson } from "@atproto/api"; 2import { PostView } from "@atproto/api/dist/client/types/app/bsky/feed/defs"; 3import { NextRequest } from "next/server"; 4 5export const runtime = "nodejs"; 6 7export async function GET(req: NextRequest) { 8 try { 9 const searchParams = req.nextUrl.searchParams; 10 const urisParam = searchParams.get("uris"); 11 12 if (!urisParam) { 13 return Response.json( 14 { error: "uris parameter is required" }, 15 { status: 400 }, 16 ); 17 } 18 19 // Parse URIs from JSON string 20 let uris: string[]; 21 try { 22 uris = JSON.parse(urisParam); 23 } catch (e) { 24 return Response.json( 25 { error: "uris must be valid JSON array" }, 26 { status: 400 }, 27 ); 28 } 29 30 if (!Array.isArray(uris)) { 31 return Response.json({ error: "uris must be an array" }, { status: 400 }); 32 } 33 34 if (uris.length === 0) { 35 return Response.json([], { 36 headers: { 37 "Cache-Control": "public, s-maxage=600, stale-while-revalidate=3600", 38 }, 39 }); 40 } 41 42 // Hydrate Bluesky URIs with post data 43 let agent = new Agent({ 44 service: "https://public.api.bsky.app", 45 }); 46 47 // Process URIs in batches of 25 48 let allPostRequests = []; 49 for (let i = 0; i < uris.length; i += 25) { 50 let batch = uris.slice(i, i + 25); 51 let batchPosts = agent.getPosts( 52 { 53 uris: batch, 54 }, 55 { headers: {} }, 56 ); 57 allPostRequests.push(batchPosts); 58 } 59 let allPosts = (await Promise.all(allPostRequests)).flatMap( 60 (r) => r.data.posts, 61 ); 62 63 const posts = lexToJson(allPosts) as PostView[]; 64 65 return Response.json(posts, { 66 headers: { 67 // Cache for 1 hour on CDN, allow stale content for 24 hours while revalidating 68 "Cache-Control": "public, s-maxage=3600, stale-while-revalidate=86400", 69 }, 70 }); 71 } catch (error) { 72 console.error("Error hydrating Bluesky posts:", error); 73 return Response.json({ error: "Failed to hydrate posts" }, { status: 500 }); 74 } 75}