"use server"; import { getIdentityData } from "actions/getIdentityData"; import { getPublicationURL } from "app/lish/createPub/getPublicationURL"; import { supabaseServerClient } from "supabase/serverClient"; import { IdResolver } from "@atproto/identity"; import type { DidCache, CacheResult, DidDocument } from "@atproto/identity"; import Client from "ioredis"; import { AtUri } from "@atproto/api"; import { Json } from "supabase/database.types"; import { idResolver } from "./idResolver"; export type Cursor = { timestamp: string; uri: string; }; export async function getReaderFeed( cursor?: Cursor | null, ): Promise<{ posts: Post[]; nextCursor: Cursor | null }> { let auth_res = await getIdentityData(); if (!auth_res?.atp_did) return { posts: [], nextCursor: null }; let query = supabaseServerClient .from("documents") .select( `*, comments_on_documents(count), document_mentions_in_bsky(count), documents_in_publications!inner(publications!inner(*, publication_subscriptions!inner(*)))`, ) .eq( "documents_in_publications.publications.publication_subscriptions.identity", auth_res.atp_did, ) .order("indexed_at", { ascending: false }) .order("uri", { ascending: false }) .limit(25); if (cursor) { query = query.or( `indexed_at.lt.${cursor.timestamp},and(indexed_at.eq.${cursor.timestamp},uri.lt.${cursor.uri})`, ); } let { data: feed, error } = await query; let posts = await Promise.all( feed?.map(async (post) => { let pub = post.documents_in_publications[0].publications!; let uri = new AtUri(post.uri); let handle = await idResolver.did.resolve(uri.host); let p: Post = { publication: { href: getPublicationURL(pub), pubRecord: pub?.record || null, uri: pub?.uri || "", }, author: handle?.alsoKnownAs?.[0] ? `@${handle.alsoKnownAs[0].slice(5)}` : null, documents: { comments_on_documents: post.comments_on_documents, document_mentions_in_bsky: post.document_mentions_in_bsky, data: post.data, uri: post.uri, indexed_at: post.indexed_at, }, }; return p; }) || [], ); const nextCursor = posts.length > 0 ? { timestamp: posts[posts.length - 1].documents.indexed_at, uri: posts[posts.length - 1].documents.uri, } : null; return { posts, nextCursor, }; } export type Post = { author: string | null; publication: { href: string; pubRecord: Json; uri: string; }; documents: { data: Json; uri: string; indexed_at: string; comments_on_documents: | { count: number; }[] | undefined; document_mentions_in_bsky: | { count: number; }[] | undefined; }; };