/* * clippr: a social bookmarking service for the AT Protocol * Copyright (c) 2025 clippr contributors. * SPDX-License-Identifier: AGPL-3.0-only */ import { SocialClipprActorDefs } from "@clipprjs/lexicons"; import type { ErrorResponse } from "./types.js"; import { getDidFromHandle, getHandleFromDid } from "../network/converters.js"; import { Database } from "../db/database.js"; import { usersTable } from "../db/schema.js"; import { eq } from "drizzle-orm"; const db = Database.getInstance().getDb(); // TODO: Stop leeching off the Bluesky CDN and get the blob directly from the user's PDS // // Get a CDN URI from a blob's CID export async function createAvatarLink( did: string, cid: string, ): Promise { return `https://cdn.bsky.app/img/avatar/plain/${did}/${cid}`; } export async function createProfileView( actor: string, ): Promise { let viewHandle; let viewDid; if (actor.startsWith("did:")) { viewDid = actor; try { viewHandle = await getHandleFromDid(viewDid); viewHandle = viewHandle.replace("at://", ""); } catch (e: unknown) { if (e instanceof Error) { return { error: "InvalidRequest", message: `Error: A queried URI does not have a valid DID or handle: ${e.message}`, }; } else { return { error: "InvalidRequest", message: "Error: A queried URI does not have a valid DID or handle: unknown error", }; } } } else { viewHandle = actor; viewHandle = viewHandle.replace("at://", ""); try { viewDid = await getDidFromHandle(viewHandle); } catch (e: unknown) { if (e instanceof Error) { return { error: "InvalidRequest", message: `Error: A queried URI does not have a valid DID or handle: ${e.message}`, }; } else { return { error: "InvalidRequest", message: "Error: A queried URI does not have a valid DID or handle: unknown error", }; } } } const dbQuery = await db .selectDistinct() .from(usersTable) .where(eq(usersTable.did, viewDid)); if (dbQuery.length === 0) { return { error: "InvalidRequest", message: "Could not find a queried URI's profile", } as ErrorResponse; } const avatarCid = dbQuery[0]?.avatar; let viewAvatar; if (avatarCid === undefined || avatarCid === null) { viewAvatar = "https://missing.avatar"; } else viewAvatar = await createAvatarLink(viewDid, avatarCid); return { $type: "social.clippr.actor.defs#profileView", did: viewDid as `did:${string}:${string}`, handle: viewHandle as `${string}.${string}`, avatar: (viewAvatar as `${string}:${string}`) || undefined, createdAt: dbQuery[0]?.createdAt.toISOString(), description: dbQuery[0]?.description || undefined, displayName: dbQuery[0]?.displayName || viewHandle, }; }