/* * clippr: a social bookmarking service for the AT Protocol * Copyright (c) 2025 clippr contributors. * SPDX-License-Identifier: AGPL-3.0-only */ import { SocialClipprActorDefs, SocialClipprFeedClip, SocialClipprFeedDefs, } from "@clipprjs/lexicons"; import type { ClipViewQuery, ErrorResponse, TagRef } from "./types.js"; import { getHandleFromDid } from "../network/converters.js"; import { Database } from "../db/database.js"; import { clipsTable } from "../db/schema.js"; import { and, eq } from "drizzle-orm"; import { createProfileView } from "./profile.js"; import { is } from "@atcute/lexicons"; import { validateHash } from "../hasher.js"; const db = Database.getInstance().getDb(); export async function createClipView( query: ClipViewQuery, ): Promise { if (!query.did.startsWith("did:")) { let did; try { did = await getHandleFromDid(query.did); } 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", }; } } query.did = did; } if (query.collection !== "social.clippr.feed.clip") { return { error: "InvalidRequest", message: "Error: A queried URI is not a proper clip", }; } const dbQuery = await db .selectDistinct() .from(clipsTable) .where( and( eq(clipsTable.did, query.did), eq(clipsTable.recordKey, query.recordKey), ), ); if (dbQuery.length === 0) { return { error: "InvalidRequest", message: "Could not find a given URI", }; } // Yes, the array thing is not ideal. if (!dbQuery[0]?.cid) { return { error: "InvalidRequest", message: "Could not find a given URI", }; } if (!(await validateHash(dbQuery[0]?.url, query.recordKey))) { return { error: "InvalidRequest", message: "Could not find a given URI", }; } const authorView: ErrorResponse | SocialClipprActorDefs.ProfileView = await createProfileView(query.did); if (!is(SocialClipprActorDefs.profileViewSchema, authorView)) { console.log(authorView); return { error: "InvalidRequest", message: "Could not validate profile view", // I can't get the error message, it seems to always assume the type is the ProfileView } as ErrorResponse; } let clipTags: TagRef[] | undefined; if (dbQuery[0]?.tags === null) { clipTags = undefined; } const clipRecord: SocialClipprFeedClip.Main = { $type: "social.clippr.feed.clip", url: dbQuery[0]?.url as `${string}:${string}`, title: dbQuery[0]?.title, description: dbQuery[0]?.description, tags: clipTags || undefined, unlisted: dbQuery[0]?.unlisted, unread: dbQuery[0]?.unread || undefined, notes: dbQuery[0]?.notes || undefined, languages: dbQuery[0]?.languages || undefined, createdAt: dbQuery[0]?.createdAt.toISOString(), }; return { cid: dbQuery[0]?.cid, uri: `at://${query.did}/${query.collection}/${query.recordKey}`, author: authorView, record: clipRecord, indexedAt: dbQuery[0]?.indexedAt.toISOString(), }; }