DuckVizBeta
SDK

Classes

Composable SDK classes for widget flow, reports, log detection, credits, and usage.

Each SDK class wraps a group of DuckViz API endpoints behind a Promise-returning and SSE-streaming interface. All classes share the same constructor options.

DuckvizWidgetFlow

Generate AI chart recommendations from a table schema.

import { DuckvizWidgetFlow } from "@duckviz/sdk";

const widgetFlow = new DuckvizWidgetFlow({ token });

const result = await widgetFlow.invoke({
  tables: [
    {
      tableName: "t_sales",
      schema: [
        { column_name: "date", column_type: "DATE" },
        { column_name: "category", column_type: "VARCHAR" },
        { column_name: "amount", column_type: "DOUBLE" },
      ],
    },
  ],
});

console.log(result.widgets); // RecommendedWidget[]

SSE streaming is supported via stream():

for await (const event of widgetFlow.stream(input)) {
  switch (event.event) {
    case "domain":
      console.log("Domain:", event.data.domain);
      break;
    case "widget":
      console.log("Widget:", event.data.title);
      break;
    case "done":
      console.log("Complete");
      break;
  }
}

DuckvizReports

Generate AI-written report sections.

import { DuckvizReports } from "@duckviz/sdk";

const reports = new DuckvizReports({ token });

const result = await reports.invoke({
  reportTitle: "Q4 Sales Report",
  systemPromptHint: "Professional executive tone",
  widgets: [
    { title: "Revenue by Category", type: "bar", description: "...", duckdbQuery: "..." },
  ],
  sections: [
    { key: "summary",  title: "Executive Summary", promptHint: "High-level overview", position: "pre" },
    { key: "analysis", title: "Analysis",          promptHint: "Detailed analysis",   position: "post" },
  ],
});

Parallel SSE streaming (3 concurrent max) via reports.stream(input). Each section emits section-start / section-complete / section-error events.

DuckvizLogFormatDetector

Detect log file format from sample lines.

import { DuckvizLogFormatDetector } from "@duckviz/sdk";

const detector = new DuckvizLogFormatDetector({ token });

const result = await detector.invoke({
  lines: [
    "2024-01-15 10:30:45 INFO [main] Application started",
    "2024-01-15 10:30:46 WARN [db] Connection pool low",
  ],
});

console.log(result.logType);    // "custom"
console.log(result.formatName); // "Custom Application Log"

DuckvizCredits

Check credit balance for the token's user.

import { DuckvizCredits } from "@duckviz/sdk";

const credits = new DuckvizCredits({ token });
const { balance, plan } = await credits.balance();

DuckvizUsage

Query usage history — one event per AI call with endpoint, credit cost, and running balance.

import { DuckvizUsage } from "@duckviz/sdk";

const usage = new DuckvizUsage({ token });
const { events } = await usage.list({ limit: 50 });
// events: Array<{ id, ts, endpoint, credits, balanceAfter }>

Accepts from and to (ISO dates) to filter a window.

Dashboard config validation

validateDashboardConfig(input: unknown): DashboardConfig parses and type-narrows an unknown blob (e.g. JSON from a request body or your DB) into a DashboardConfig. It's fail-fast — the first invalid field throws DashboardConfigError with the path that failed; subsequent fields are not checked.

import {
  validateDashboardConfig,
  DashboardConfigError,
  type DashboardConfig,
} from "@duckviz/sdk";

export async function POST(req: Request) {
  const body: unknown = await req.json();

  let config: DashboardConfig;
  try {
    config = validateDashboardConfig(body);
  } catch (e) {
    if (e instanceof DashboardConfigError) {
      // e.message is "DashboardConfig.<path>: <reason>"
      // e.path is the dotted path, e.g. "widgets[2].dataKey"
      return Response.json(
        { error: "Invalid dashboard config", path: e.path, reason: e.message },
        { status: 400 },
      );
    }
    throw e; // unexpected — re-throw
  }

  // From here, `config` is a fully-typed DashboardConfig.
  await saveToDb(config);
  return Response.json({ ok: true });
}

What gets validated

  • widgets — must be an array; each widget must have a non-empty string id, type, title, and dataKey. Optional fields (description, config, layout) are loosely checked.
  • grid — if present, cols and rowHeight must be numbers; margin must be a 2-tuple of numbers.
  • name, description, dataset — optional strings.
  • theme — shape-checked, but token values are passed through without parsing.

It does not validate that dataKey is real SQL or that type matches a known chart string — that's a runtime concern handled by @duckviz/dashboard's validateChartAliases after the query runs.

When to use it

  • Before persisting a config you received over the wire (form post, API, file upload)
  • Before forwarding a config to <Dashboard config={...}> from untrusted input
  • In tests, to make sure your factory functions emit valid configs

For trusted internal configs (e.g. from a typed DashboardConfig constant in your codebase), validation is redundant — TypeScript already covers it.