@kolistat/bedevere-wise
v0.14.0
Published
Open SAS, SPSS, Stata, Parquet, and Excel files in your browser. Query them with SQL — no install, no upload.
Maintainers
Readme
@kolistat/bedevere-wise
Embeddable browser components for DuckDB-WASM-backed data exploration:
SpreadsheetVisualizer— canvas-rendered grid; virtually scrolled, HiDPI-sharp.ColumnStatsVisualizer— per-column summary stats + value-filter UI.ChartVisualizer— Vega-Lite renderer forstats_duck'sVISUALIZE … DRAWoutput.EmbedSqlEditor— slim CodeMirror SQL editor with Bedevere's PostgreSQL-extended dialect.DuckDBService+DuckDBDataProvider— DuckDB-WASM runtime wrapper + bridge to the UI components.
These are the same components that compose the standalone web app at bedeverewise.app. Also consumed by tlf-studio for clinical-trial pipeline inspection.
Status: pre-1.0. Shipping on the
@nextdist-tag while the embedding API settles. Breaking changes are possible between0.xminor versions (the CHANGELOG flags them). Pin to an exact version in production.
Install
bun add @kolistat/bedevere-wise@next
# Peer dependencies — install one shared copy of each in your tree:
bun add @duckdb/duckdb-wasm \
@codemirror/autocomplete @codemirror/commands @codemirror/lang-sql \
@codemirror/language @codemirror/search @codemirror/state \
@codemirror/view @lezer/highlight codemirror \
vega-embedAll peer deps are required if you import from the package's main entry today. See Bundler compatibility for the rationale and the WASM-free entry split (/ui, /app, /ipc).
Quick start
import {
DuckDBService,
DuckDBDataProvider,
SpreadsheetVisualizer,
ColumnStatsVisualizerFocusable,
} from "@kolistat/bedevere-wise";
import "@kolistat/bedevere-wise/style.css";
const duck = new DuckDBService();
await duck.initialize();
// Point DuckDB at a remote dataset; the host must serve permissive CORS.
await duck.registerFileURL("adsl.parquet", "https://example.org/adsl.parquet");
await duck.executeQuery(
`CREATE OR REPLACE TABLE adsl AS SELECT * FROM read_parquet('adsl.parquet')`,
);
const provider = new DuckDBDataProvider(duck, "adsl", "adsl.parquet");
// One shared stats panel, mounted next to the spreadsheet:
const stats = new ColumnStatsVisualizerFocusable(
document.querySelector("#stats")!,
null,
);
const grid = new SpreadsheetVisualizer(
document.querySelector("#grid")!,
provider,
{ minHeight: 240, minWidth: 320 },
stats,
"my-app-grid",
);
await grid.initialize();Embedding surface
The package ships two tiers of exports.
Embedding tier — recommended
Components in this tier accept their dependencies via constructor; no module-level singleton reach-through. Safe to mount inside any host app.
| Export | Purpose |
| --- | --- |
| DuckDBService | DuckDB-WASM runtime wrapper. One instance per app. |
| DuckDBDataProvider | Implements DataProvider over a DuckDB table. |
| DataProvider (interface) | The per-dataset integration boundary. Implement your own to feed rows from anywhere — HTTP, IPC, a server. |
| Backend (interface) | The SQL-engine boundary. Implement to point BedevereApp at a non-WASM engine (native IPC, remote relay). Optional exportTable(opts) writes a whole table to Parquet / JSON / SAS / SPSS — ExportFormat, ExportTableOptions, ExportResult, and EXPORT_FORMATS are exported for it. |
| SpreadsheetVisualizer | Canvas-rendered spreadsheet. |
| ColumnStatsVisualizer / ColumnStatsVisualizerFocusable | Column stats + filter panel; share one across many spreadsheets. |
| ChartVisualizer | Renders Vega-Lite specs produced by stats_duck's VISUALIZE … DRAW. |
| EmbedSqlEditor | Slim CodeMirror SQL editor with the Bedevere dialect + tokyonight palette. |
| Type helpers (isNumericType, normalizeDuckDBType, dataTypeCategory, …) | For consumers writing custom DataProviders. |
The UI components (SpreadsheetVisualizer, ColumnStatsVisualizer, ChartVisualizer, EmbedSqlEditor) have no hard dependency on DuckDB-WASM — they consume the DataProvider interface and Vega specs respectively. A consumer can ignore DuckDBService / DuckDBDataProvider entirely and supply their own DataProvider over an alternative backend (HTTP API, native IPC, an in-memory pipeline, …).
App-shell tier — @kolistat/bedevere-wise/app
The full standalone-app shell as composable pieces: BedevereApp, TabManager, ControlPanel, StatusBar, CommandBar, plus the PersistenceService singleton. BedevereApp is backend-agnostic — pass options.backend (there is no built-in default), so importing from /app pulls no DuckDB-WASM. Pair it with /duckdb for the in-browser engine, or hand it an IpcBackend / remote relay (this is exactly how bedevere-desktop drives the same UI against native DuckDB):
import { BedevereApp } from "@kolistat/bedevere-wise/app";
import { DuckDBService } from "@kolistat/bedevere-wise/duckdb";
import "@kolistat/bedevere-wise/style.css";
const backend = new DuckDBService();
await backend.initialize();
const app = new BedevereApp(document.getElementById("app")!, "1.0.0", { backend });
await app.initAsync();These shells assume module-level singletons (CommandRegistry, EnvironmentService, KeymapService, PersistenceService) and expect one BedevereApp per page. If you only need a piece of the UI rather than the whole shell, prefer the component tier above.
Theming
The package ships four themes as CSS custom-property sets, selected by a single body class — exactly one is applied at a time:
| Body class | Theme |
| --- | --- |
| theme-dark | GitHub-Dark — the default dark |
| theme-light | Light (warm-neutral) |
| theme-classic-dark | Tokyonight Storm |
| theme-classic-light | Tokyonight Day |
Override the tokens in your own stylesheet, after importing the package CSS (see dist/style.css for the full token list):
body.theme-dark {
--bg: #1f1f1f;
--fg: #e1e4e8;
/* ... */
}Switching the body class re-renders theme-sensitive canvas surfaces (the spreadsheet repaints; the chart re-embeds with a matching Vega palette). BedevereApp manages this class for you and exposes setTheme().
Bundler compatibility
The package is browser-only and currently Vite-friendly. DuckDB-WASM, which DuckDBService depends on, ships its worker scripts as separate JS files referenced via Vite's ?url import syntax. The compiled bundle (dist/index.es.js) preserves these ?url imports verbatim; resolving them is your bundler's job.
| Bundler | Status |
| --- | --- |
| Vite | Works out of the box. This is the supported path. |
| webpack 5 | Works with asset/resource rules for the worker URLs. See the DuckDB-WASM docs for setup. |
| Bun bundler / esbuild / Parcel | The ?url suffix isn't resolved natively; needs custom plugins or loader config. Untested. |
| SSR / Node / Bun runtime | Not supported. The DuckDB worker code requires browser APIs at module load. |
The ?url worker chain lives only behind the /duckdb entry. If your bundler can't resolve ?url (or you simply don't want DuckDB-WASM in your bundle), import from the WASM-free entries instead and bring your own engine:
| Entry | Pulls DuckDB-WASM? | Use for |
| --- | --- | --- |
| @kolistat/bedevere-wise/ui | No | Individual UI components over your own DataProvider. |
| @kolistat/bedevere-wise/app | No | The full app shell (BedevereApp) with an injected Backend. |
| @kolistat/bedevere-wise/duckdb | Yes | The in-browser DuckDBService engine (the ?url chain). |
| @kolistat/bedevere-wise/ipc | No | IpcBackend for a native/remote DuckDB over WebSocket. |
| @kolistat/bedevere-wise (root) | Yes | Back-compat barrel; re-exports /duckdb, so it pulls the chain. |
Local development against this package
The package's source lives in bedevere-wise (active development happens on the current dev-X.Y branch). To hack on both this and a consumer at once:
# in bedevere-wise/
bun run build:lib # produces dist/
bun link # registers @kolistat/bedevere-wise locally
# in your consumer app/
bun link @kolistat/bedevere-wiseAfter source changes in bedevere-wise, re-run bun run build:lib to refresh the linked dist/. The consumer's Vite dev server picks up the new code on next reload.
Source + standalone app
Source code: github.com/KoliStat/bedevere-wise. The standalone web app at bedeverewise.app is built from the same source. End-user docs and screenshots live on the Bedevere Wise app site (it's a desktop-only browser app; mobile isn't supported yet).
License
MIT — see LICENSE.
