import type { CommentListPage } from "#lib/api/comment.ts"; import type { BobbinContext } from "#lib/api/client.ts"; import { REACTION_AUTHOR_DOCS } from "#lib/api/descriptors.ts"; import { enrich, miniDocOf, target, type Sidecar } from "#lib/api/enrich.ts"; import { INVALID_HANDLE } from "#lib/api/identity.ts"; import { orNull } from "#lib/api/load.ts"; import type { ReactionListPage } from "#lib/api/reaction.ts"; import { rkeyFromUri } from "#lib/api/uri.ts"; import { buildCommentThreads, commentAuthorOf, commentModerationOf, listCommentItems, type CommentThread, type CommentView, type ThreadInput } from "#lib/components/comment/comments.ts"; import { buildReactions, type ReactionGroup } from "#lib/components/reaction/reactions.ts"; import type { MarkupContext } from "#lib/markup/paths.ts"; import { renderMarkup } from "#lib/markup/render.ts"; export const toThreadInputs = async ( items: CommentListPage["items"], docs: Sidecar, markupCtx: MarkupContext, extra?: (uri: string) => Partial ): Promise => Promise.all( items.map(async (item): Promise => { const author = commentAuthorOf(docs, item); const body = item.body?.text ?? ""; return { comment: { uri: item.uri, cid: item.cid, rkey: rkeyFromUri(item.uri), authorDid: author.did, authorHandle: author.handle ?? INVALID_HANDLE, moderation: commentModerationOf(docs, item), createdAt: item.createdAt, body, bodyHtml: body ? await orNull(renderMarkup(body, markupCtx)) : null, ...extra?.(item.uri) }, replyTo: item.replyTo?.uri ?? null, replyToCid: item.replyTo?.cid }; }) ); const loadReactions = ( ctx: BobbinContext, subject: string, viewerDid: string | undefined ): Promise => enrich(ctx, { xrpc: "org.tangled.feed.listReactions", params: { subject, order: "asc", limit: 100 }, enrich: [target(REACTION_AUTHOR_DOCS, ["items[].uri", "items[].value.x-tngl-editor"])] }) .then((page) => buildReactions( page.output.items, viewerDid, (did) => miniDocOf(page.data, did, REACTION_AUTHOR_DOCS)?.handle ?? INVALID_HANDLE ) ) .catch(() => []); export const loadCommentThreads = async ( ctx: BobbinContext, subjectUri: string, markupCtx: MarkupContext, viewerDid: string | undefined ): Promise => { const { items, docs } = await listCommentItems(ctx, subjectUri); const reactions = new Map( await Promise.all( items.map( async (item) => [item.uri, await loadReactions(ctx, item.uri, viewerDid)] as const ) ) ); return buildCommentThreads( await toThreadInputs(items, docs, markupCtx, (uri) => ({ reactions: reactions.get(uri) })) ); };