import type { Attachment } from "@/lib/chat/types"; import type { ValidatedAttachment } from "@/lib/chat/attachments"; import type { Queryable } from "@/lib/db/types"; type AttachmentRow = { id: string; original_name: string; content_type: string; byte_size: number; gate_file_id: string | null; object_key: string | null; }; export type StoredAttachment = Attachment & { gateFileId: string | null; objectKey: string | null; }; export type GateAttachmentMetadata = ValidatedAttachment & { gateFileId: string }; export async function createPendingAttachment( database: Queryable, userId: string, attachment: GateAttachmentMetadata, ): Promise { const result = await database.query( `INSERT INTO chat_attachments (user_id, original_name, content_type, byte_size, gate_file_id, state, expires_at) VALUES ($1::uuid, $2, $3, $4, $5, 'pending', now() + interval '24 hours') RETURNING id, original_name, content_type, byte_size, gate_file_id, object_key`, [userId, attachment.name, attachment.contentType, attachment.size, attachment.gateFileId], ); return mapStoredAttachment(result.rows[0]); } export async function getOwnedAttachment( database: Queryable, userId: string, id: string, ): Promise { const result = await database.query( `SELECT id, original_name, content_type, byte_size, gate_file_id, object_key FROM chat_attachments WHERE id = $1 AND user_id = $2`, [id, userId], ); return result.rows[0] ? mapStoredAttachment(result.rows[0]) : null; } export async function attachPendingAttachments( database: Queryable, userId: string, messageId: string, ids: string[], ): Promise { if (ids.length !== new Set(ids).size) throw new Error("Duplicate attachment IDs"); const result = await database.query( `UPDATE chat_attachments SET message_id = $3, state = 'attached', expires_at = 'infinity' WHERE id = ANY($1::uuid[]) AND user_id = $2 AND state = 'pending' AND expires_at > now() RETURNING id, original_name, content_type, byte_size, gate_file_id, object_key`, [ids, userId, messageId], ); if (result.rows.length !== ids.length) throw new Error("Attachment not found"); return result.rows.map(mapStoredAttachment); } function mapAttachment(row: AttachmentRow): Attachment { return { id: row.id, name: row.original_name, contentType: row.content_type, size: Number(row.byte_size) }; } function mapStoredAttachment(row: AttachmentRow): StoredAttachment { return { ...mapAttachment(row), gateFileId: row.gate_file_id, objectKey: row.object_key, }; }