carbon-tokenization / frontend /src /editor /embeds /embed-data-store.ts
tfrere's picture
tfrere HF Staff
feat(editor): embed studio with data files and agent-aware editing
8fc8501
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<EmbedDataFile>("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<typeof createEmbedDataStore>;