feat: add duckdb-wasm singleton for client-side parquet queries

Adds src/utils/duckdbClient.js, a lazy-initialized getDb() singleton
wrapping the AsyncDuckDB MVP (single-threaded) wasm bundle. Pins
@duckdb/duckdb-wasm to ^1.32.0 (npm's latest dist-tag currently points
at a -dev prerelease). Excludes the package from Vite's dev-server
dependency pre-bundling so its worker/wasm ?url imports resolve
correctly.

Verified live in the browser under the /crdc-demo/ base path: wasm and
worker assets load with 200, and a SELECT 42 query round-trips
correctly through the singleton, confirming the risk flagged in the
design spec (duckdb-wasm loading correctly from a subpath-served Vite
dev server) does not materialize.
This commit is contained in:
2026-08-11 08:49:05 -04:00
parent 991a6912f8
commit 88b09a5d2e
4 changed files with 271 additions and 0 deletions
+26
View File
@@ -0,0 +1,26 @@
/**
* Lazy-initialized singleton AsyncDuckDB instance running the single-threaded
* MVP wasm bundle only — never eh/coi, which need Cross-Origin-Opener-Policy /
* Cross-Origin-Embedder-Policy response headers this static host doesn't send.
* See docs/superpowers/specs/2026-08-11-empirical-draws-wasm-design.md.
*/
let dbPromise = null
/** @returns {Promise<import('@duckdb/duckdb-wasm').AsyncDuckDB>} */
export function getDb() {
if (!dbPromise) dbPromise = initDb()
return dbPromise
}
async function initDb() {
const duckdb = await import('@duckdb/duckdb-wasm')
const mvpWorkerUrl = (await import('@duckdb/duckdb-wasm/dist/duckdb-browser-mvp.worker.js?url')).default
const mvpWasmUrl = (await import('@duckdb/duckdb-wasm/dist/duckdb-mvp.wasm?url')).default
const worker = new Worker(mvpWorkerUrl)
const logger = new duckdb.ConsoleLogger(duckdb.LogLevel.WARNING)
const db = new duckdb.AsyncDuckDB(logger, worker)
await db.instantiate(mvpWasmUrl, null)
return db
}