spb/zyquo-cloud-web Public MIT
Zyquo Cloud Web — every cloud model, one beautiful chat, entirely in your browser.
TypeScript 81.9%
CSS 8.9%
JavaScript 7.5%
Shell 1.1%
HTML 0.6%
1/*2 * conversations.ts3 * Zyquo Cloud Web4 *5 * Author: Simon-Pierre Boucher6 * Mail: contact@spboucher.ai7 *8 * Conversation persistence — IndexedDB (namespace zyquo.cloud.web), one9 * record per conversation, autosaved on every mutation by the store layer.10 * Includes schema versioning/migration for stored records.11 */1213import type { Conversation } from '../types'14import { dbClear, dbDelete, dbGetAll, dbPut, STORE_CONVERSATIONS } from './db'1516/** Bump when the stored Conversation shape changes; migrate() upgrades old records. */17const SCHEMA_VERSION = 11819interface StoredConversation extends Conversation {20 schemaVersion?: number21}2223/** Upgrades a stored record from any older schema to the current one. */24function migrate(record: StoredConversation): Conversation {25 const version = record.schemaVersion ?? 126 // v1 is current — future migrations chain here (v1 → v2 → …).27 void version28 const { schemaVersion: _schemaVersion, ...conversation } = record29 return {30 ...conversation,31 parameters: conversation.parameters ?? {},32 messages: conversation.messages ?? [],33 pinned: conversation.pinned ?? false,34 hasAutoTitle: conversation.hasAutoTitle ?? true,35 }36}3738/** All conversations, newest-first by updatedAt. */39export async function loadConversations(): Promise<Conversation[]> {40 const records = await dbGetAll<StoredConversation>(STORE_CONVERSATIONS)41 return records.map(migrate).sort((a, b) => b.updatedAt - a.updatedAt)42}4344export async function saveConversation(conversation: Conversation): Promise<void> {45 const record: StoredConversation = { ...conversation, schemaVersion: SCHEMA_VERSION }46 await dbPut(STORE_CONVERSATIONS, record)47}4849export async function deleteConversation(id: string): Promise<void> {50 await dbDelete(STORE_CONVERSATIONS, id)51}5253export async function clearConversations(): Promise<void> {54 await dbClear(STORE_CONVERSATIONS)55}5657/** Case-insensitive search across titles and all message text. */58export function matchesSearch(conversation: Conversation, query: string): boolean {59 const q = query.trim().toLowerCase()60 if (q === '') return true61 if (conversation.title.toLowerCase().includes(q)) return true62 return conversation.messages.some((message) => message.text.toLowerCase().includes(q))63}64