import { eq, desc, asc } from "drizzle-orm"; import type { Db } from "@paperclipai/db"; import { chatFiles, chatFileReferences } from "@paperclipai/db"; const CODE_MIME_TYPES = new Set([ "text/javascript", "text/typescript", "application/javascript", "application/typescript", "text/css", "text/html", "application/json", "text/x-python", "text/x-java", "text/x-c", "text/x-cpp", "text/x-csharp", "text/x-ruby", "text/x-go", "text/x-rust", "text/x-swift", "text/x-kotlin", "text/x-php", "text/x-shellscript", "application/x-sh", "text/x-yaml", "application/x-yaml", "text/x-toml", ]); const DOCUMENT_MIME_TYPES = new Set([ "application/pdf", "text/plain", "text/markdown", "text/csv", ]); export function deriveCategory(mimeType: string): string { const mt = mimeType.toLowerCase(); if (mt.startsWith("image/")) return "image"; if (CODE_MIME_TYPES.has(mt)) return "code"; if (DOCUMENT_MIME_TYPES.has(mt)) return "document"; return "other"; } export function chatFileService(db: Db) { return { create( companyId: string, data: Omit, ) { return db .insert(chatFiles) .values({ ...data, companyId }) .returning() .then((rows) => rows[0]!); }, getById(id: string) { return db .select() .from(chatFiles) .where(eq(chatFiles.id, id)) .then((rows) => rows[0] ?? null); }, listByConversation(conversationId: string, opts?: { limit?: number }) { const limit = opts?.limit ?? 50; return db .select() .from(chatFiles) .where(eq(chatFiles.conversationId, conversationId)) .orderBy(desc(chatFiles.createdAt)) .limit(limit); }, listByMessage(messageId: string) { return db .select() .from(chatFiles) .where(eq(chatFiles.messageId, messageId)) .orderBy(asc(chatFiles.createdAt)); }, createReference(data: { fileId: string; conversationId: string; messageId?: string; }) { return db .insert(chatFileReferences) .values(data) .returning() .then((rows) => rows[0]!); }, listReferences(fileId: string) { return db .select() .from(chatFileReferences) .where(eq(chatFileReferences.fileId, fileId)); }, attachToMessage(fileId: string, messageId: string) { return db .update(chatFiles) .set({ messageId, updatedAt: new Date() }) .where(eq(chatFiles.id, fileId)) .returning() .then((rows) => rows[0]!); }, promoteToProject(fileId: string, projectId: string) { return db .update(chatFiles) .set({ projectId, updatedAt: new Date() }) .where(eq(chatFiles.id, fileId)) .returning() .then((rows) => rows[0] ?? null); }, markAsPlaceholder(fileId: string) { return db .update(chatFiles) .set({ category: "placeholder", updatedAt: new Date() }) .where(eq(chatFiles.id, fileId)) .returning() .then((rows) => rows[0] ?? null); }, }; }