import * as Y from "yjs"; /** * Metadata describing a data file uploaded into the embed data store. * * Kept intentionally lean (strings + small numbers) so it can live * alongside the raw content inside a single Y.Map entry without * bloating the document size. */ export interface EmbedDataFileMeta { name: string; /** Extension without leading dot, lowercased: "csv" | "tsv" | "json" | "txt" */ ext: string; /** Size of the stored text content in bytes (UTF-8). */ size: number; /** Uploader user id (if available). */ uploader?: string; /** Epoch ms when the file was added. */ addedAt: number; /** Light metadata computed client-side after parsing. */ rowCount?: number; columns?: string[]; } export interface EmbedDataFile { meta: EmbedDataFileMeta; /** Raw text content (UTF-8). */ content: string; } /** * Collaborative store for tabular/textual data files attached to a * document. Each key is a filename (e.g. "sales.csv") and the value is * an `EmbedDataFile` object (meta + raw text content). * * These files are accessible to the Embed Studio AI via tool calls so * charts can reference user-provided datasets. The store is backed by * `Y.Map("embed-data")` for realtime collaboration. */ export function createEmbedDataStore(ydoc: Y.Doc) { const ymap = ydoc.getMap("embed-data"); function get(name: string): EmbedDataFile | undefined { return ymap.get(name); } function getContent(name: string): string { return ymap.get(name)?.content ?? ""; } function getMeta(name: string): EmbedDataFileMeta | undefined { return ymap.get(name)?.meta; } function has(name: string): boolean { return ymap.has(name); } function set(file: EmbedDataFile) { ymap.set(file.meta.name, file); } function remove(name: string) { ymap.delete(name); } function rename(oldName: string, newName: string) { const file = ymap.get(oldName); if (!file) return; ydoc.transact(() => { ymap.set(newName, { ...file, meta: { ...file.meta, name: newName } }); ymap.delete(oldName); }); } function keys(): string[] { return Array.from(ymap.keys()); } function list(): EmbedDataFileMeta[] { const items: EmbedDataFileMeta[] = []; ymap.forEach((file) => { items.push(file.meta); }); return items.sort((a, b) => a.name.localeCompare(b.name)); } function observe(callback: () => void) { ymap.observe(callback); return () => ymap.unobserve(callback); } return { get, getContent, getMeta, has, set, remove, rename, keys, list, observe, }; } export type EmbedDataStore = ReturnType;