Bahini
Open app

Core

Dashboards & data

Push rows from an external system into named datasets, define dashboards as code, and set threshold alerts on your metrics. The programmatic twin of the in-product dashboard.publish tool.

Publish a dataset#

rows is an array of flat { column: value } objects. mode: "append" accumulates (time-series); the default "replace" overwrites. Reusing a dataset id updates the same widgets bound to it. Requires a write-scoped key.

 
ts
await bahini.publishDataset({
  dataset: "store-sales",
  rows: [
    { store: "Dhaka",     revenue: 128400, orders: 512 },
    { store: "Chittagong", revenue: 96150, orders: 388 },
  ],
});

Have a CSV instead? publishDatasetFromCsv parses it client-side (quoted fields, CRLF, BOM, numeric coercion) then publishes.

 
ts
await bahini.publishDatasetFromCsv("store-sales", csvString, {
  mode: "append",
});
The server scrubs string cells of PII/secrets before storing — the response's redactedCount tells you how many were touched.

Define a dashboard as code#

upsertDashboard matches by title (create-or-update). Widgets are flat: a type, the datasetKey they chart, and field mappings. Reusing a title updates that board.

 
ts
const board = await bahini.upsertDashboard({
  title: "Store performance",
  widgets: [
    { type: "number", datasetKey: "store-sales", y: "revenue",
      agg: "sum", format: "currency", title: "Total revenue" },
    { type: "bar", datasetKey: "store-sales", x: "store", y: "revenue",
      sort: "desc", title: "Revenue by store" },
  ],
});
console.log(board.url);

Read data back#

 
ts
const { datasets } = await bahini.listDatasets();
const data = await bahini.getDataset("store-sales"); // includes rows
const full = await bahini.getDashboard(board.id);     // widgets + resolved rows

Metric alerts#

createAlert(input)

Fires when agg(column) of a dataset crosses the threshold on the next publish. mode: "change" compares the % change vs the previous publish; "stale"fires when a dataset hasn't published in threshold hours.

 
ts
await bahini.createAlert({
  name: "Revenue dropped",
  datasetKey: "store-sales",
  column: "revenue",
  agg: "sum",
  op: "lt",
  threshold: 100_000,
});