import type { AtpAgent } from "@atproto/api"; import type { Database } from "@atbb/db"; import { categories, forums } from "@atbb/db"; import { eq, and } from "drizzle-orm"; import { deriveSlug } from "../slug.js"; interface CreateCategoryInput { name: string; description?: string; slug?: string; sortOrder?: number; } interface CreateCategoryResult { created: boolean; skipped: boolean; uri?: string; cid?: string; existingName?: string; } /** * Create a space.atbb.forum.category record on the Forum DID's PDS * and insert it into the database. * Idempotent: skips if a category with the same name already exists. */ export async function createCategory( db: Database, agent: AtpAgent, forumDid: string, input: CreateCategoryInput ): Promise { // Check if category with this name already exists const [existing] = await db .select() .from(categories) .where(and(eq(categories.did, forumDid), eq(categories.name, input.name))) .limit(1); if (existing) { return { created: false, skipped: true, uri: `at://${existing.did}/space.atbb.forum.category/${existing.rkey}`, cid: existing.cid, existingName: existing.name, }; } // Look up forum row for FK reference (optional — null if forum not yet in DB) const [forum] = await db .select() .from(forums) .where(and(eq(forums.did, forumDid), eq(forums.rkey, "self"))) .limit(1); if (!forum?.id) { console.warn( "Forum record not found in DB — inserting category with forumId: null", JSON.stringify({ forumDid }) ); } const slug = input.slug ?? deriveSlug(input.name); const now = new Date(); const response = await agent.com.atproto.repo.createRecord({ repo: forumDid, collection: "space.atbb.forum.category", record: { $type: "space.atbb.forum.category", name: input.name, ...(input.description && { description: input.description }), slug, ...(input.sortOrder !== undefined && { sortOrder: input.sortOrder }), createdAt: now.toISOString(), }, }); const rkey = response.data.uri.split("/").pop()!; await db.insert(categories).values({ did: forumDid, rkey, cid: response.data.cid, name: input.name, description: input.description ?? null, slug, sortOrder: input.sortOrder ?? null, forumId: forum?.id ?? null, createdAt: now, indexedAt: now, }); return { created: true, skipped: false, uri: response.data.uri, cid: response.data.cid, }; }