Files
cobble/src/functions/backend/db/bot-graphics/create-bot-graphic.ts
T
tbenandClaude Opus 5.5 bea656ade8 Add bot graphics
Bots can now show a concept as a visual: create_graphic (with
update_graphic, read_graphic and list_graphics, on every run, no computer
needed) stores one HTML document in bot_graphics, per user like the
conversation, and the chat renders its [graphic:ID] ref as an inline card
sized to fit, with a large view and a page of its own (no rail).

Graphic HTML is treated as hostile: it is only served at /graphics/<id>
with a CSP sandbox allowing scripts under an origin of its own and no
network, loading only the vendored Chart.js and Mermaid from
/graphics-lib/. The document carries the app's theme vars and scrollbars,
reports its height to the thread, and a frame that navigates away is
closed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-27 08:11:15 +01:00

54 lines
1.5 KiB
TypeScript

import BunSQLite from "@moduletrace/bun-sqlite";
import type { BUN_SQLITE_COBBLE_BOT_GRAPHICS, BunSQLiteTables } from "@/db/types/db";
import checkGraphicInput from "./check-graphic-input";
type Params = {
user_id: number | string;
bot_id: number | string;
session_id?: number | string | null;
workspace_id?: number | string | null;
/**
* The run that made it, so its message is linked once posted.
*/
job_id?: number | string | null;
title: string;
html: string;
};
/**
* Stores a graphic a bot made for a user. Returns its id.
*/
export default async function createBotGraphic({
user_id,
bot_id,
session_id,
workspace_id,
job_id,
title,
html,
}: Params) {
const checked = checkGraphicInput({ title, html });
const res = await BunSQLite.insert<BUN_SQLITE_COBBLE_BOT_GRAPHICS, (typeof BunSQLiteTables)[number]>({
table: "bot_graphics",
data: [
{
title: checked.title,
html: checked.html,
version: 1,
user_id: Number(user_id),
bot_id: Number(bot_id),
session_id: session_id ? Number(session_id) : undefined,
workspace_id: workspace_id ? Number(workspace_id) : undefined,
job_id: job_id ? Number(job_id) : undefined,
},
],
});
const id = Number(res.singleRes?.id || res.postInsertReturn?.insertId);
if (!res.success || !id) throw new Error(`Couldn't store the graphic: ${res.msg}`);
return id;
}