a tool for shared writing and social publishing
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

add quotes api endpoint

+77
+77
app/api/bsky/quotes/route.ts
··· 1 + import { Agent, lexToJson } from "@atproto/api"; 2 + import { cookies } from "next/headers"; 3 + import { NextRequest } from "next/server"; 4 + import { createOauthClient } from "src/atproto-oauth"; 5 + import { supabaseServerClient } from "supabase/serverClient"; 6 + 7 + export const runtime = "nodejs"; 8 + 9 + async function getAuthenticatedAgent(): Promise<Agent | null> { 10 + try { 11 + const cookieStore = await cookies(); 12 + const authToken = 13 + cookieStore.get("auth_token")?.value || 14 + cookieStore.get("external_auth_token")?.value; 15 + 16 + if (!authToken || authToken === "null") return null; 17 + 18 + const { data } = await supabaseServerClient 19 + .from("email_auth_tokens") 20 + .select("identities(atp_did)") 21 + .eq("id", authToken) 22 + .eq("confirmed", true) 23 + .single(); 24 + 25 + const did = data?.identities?.atp_did; 26 + if (!did) return null; 27 + 28 + const oauthClient = await createOauthClient(); 29 + const session = await oauthClient.restore(did); 30 + return new Agent(session); 31 + } catch (error) { 32 + console.error("Failed to get authenticated agent:", error); 33 + return null; 34 + } 35 + } 36 + 37 + export async function GET(req: NextRequest) { 38 + try { 39 + const searchParams = req.nextUrl.searchParams; 40 + const uri = searchParams.get("uri"); 41 + const cursor = searchParams.get("cursor"); 42 + const limit = searchParams.get("limit"); 43 + 44 + if (!uri) { 45 + return Response.json( 46 + { error: "uri parameter is required" }, 47 + { status: 400 }, 48 + ); 49 + } 50 + 51 + // Try to use authenticated agent if user is logged in, otherwise fall back to public API 52 + let agent = await getAuthenticatedAgent(); 53 + if (!agent) { 54 + agent = new Agent({ 55 + service: "https://public.api.bsky.app", 56 + }); 57 + } 58 + 59 + const response = await agent.app.bsky.feed.getQuotes({ 60 + uri, 61 + limit: limit ? parseInt(limit, 10) : 50, 62 + cursor: cursor || undefined, 63 + }); 64 + 65 + const result = lexToJson(response.data); 66 + 67 + return Response.json(result, { 68 + headers: { 69 + // Cache for 5 minutes on CDN, allow stale content for 1 hour while revalidating 70 + "Cache-Control": "public, s-maxage=300, stale-while-revalidate=3600", 71 + }, 72 + }); 73 + } catch (error) { 74 + console.error("Error fetching Bluesky quotes:", error); 75 + return Response.json({ error: "Failed to fetch quotes" }, { status: 500 }); 76 + } 77 + }