/* * conversations.ts * Zyquo Cloud Web * * Author: Simon-Pierre Boucher * Mail: contact@spboucher.ai * * Conversation persistence — IndexedDB (namespace zyquo.cloud.web), one * record per conversation, autosaved on every mutation by the store layer. * Includes schema versioning/migration for stored records. */ import type { Conversation } from '../types' import { dbClear, dbDelete, dbGetAll, dbPut, STORE_CONVERSATIONS } from './db' /** Bump when the stored Conversation shape changes; migrate() upgrades old records. */ const SCHEMA_VERSION = 1 interface StoredConversation extends Conversation { schemaVersion?: number } /** Upgrades a stored record from any older schema to the current one. */ function migrate(record: StoredConversation): Conversation { const version = record.schemaVersion ?? 1 // v1 is current — future migrations chain here (v1 → v2 → …). void version const { schemaVersion: _schemaVersion, ...conversation } = record return { ...conversation, parameters: conversation.parameters ?? {}, messages: conversation.messages ?? [], pinned: conversation.pinned ?? false, hasAutoTitle: conversation.hasAutoTitle ?? true, } } /** All conversations, newest-first by updatedAt. */ export async function loadConversations(): Promise { const records = await dbGetAll(STORE_CONVERSATIONS) return records.map(migrate).sort((a, b) => b.updatedAt - a.updatedAt) } export async function saveConversation(conversation: Conversation): Promise { const record: StoredConversation = { ...conversation, schemaVersion: SCHEMA_VERSION } await dbPut(STORE_CONVERSATIONS, record) } export async function deleteConversation(id: string): Promise { await dbDelete(STORE_CONVERSATIONS, id) } export async function clearConversations(): Promise { await dbClear(STORE_CONVERSATIONS) } /** Case-insensitive search across titles and all message text. */ export function matchesSearch(conversation: Conversation, query: string): boolean { const q = query.trim().toLowerCase() if (q === '') return true if (conversation.title.toLowerCase().includes(q)) return true return conversation.messages.some((message) => message.text.toLowerCase().includes(q)) }