This file provides guidance to AI coding assistants working on the Node.js bindings.
For the overall repository architecture, Rust crate structure, and contribution conventions, see the root AGENTS.md.
For documentation conventions specific to JavaScript/TypeScript, see the Documentation Style Guide.
hyperdb-api-node is a napi-rs native addon that exposes the Rust hyperdb-api crate to JavaScript and TypeScript. The Rust side (src/*.rs) compiles to a .node shared library; the JS side (index.js, index.d.ts, pool.mjs, arrow.mjs) adds ergonomic wrappers on top.
┌──────────────────────────────────────────────────┐
│ JS/TS application code │
├──────────────────────────────────────────────────┤
│ index.js — native loader + JS extensions │
│ index.d.ts — hand-written TypeScript decls │
│ pool.mjs — ConnectionPool (pure JS) │
│ arrow.mjs — Arrow convenience helpers │
├──────────────────────────────────────────────────┤
│ src/*.rs — napi-rs bindings (Rust → JS) │
│ Uses hyperdb-api + hyperdb-api-core │
├──────────────────────────────────────────────────┤
│ hyperdb-api — Pure Rust high-level API │
│ hyperdb-api-core::client — TCP/gRPC, wire protocol │
└──────────────────────────────────────────────────┘
| File | Purpose |
|---|---|
src/lib.rs |
Rust module declarations |
src/connection.rs |
napi-rs Connection, ConnectionBuilder |
src/process.rs |
napi-rs HyperProcess |
src/inserter.rs |
napi-rs Inserter |
src/catalog.rs |
napi-rs Catalog |
src/result.rs |
napi-rs RowData, ResultColumnInfo |
src/query_stream.rs |
napi-rs QueryStream |
src/columnar.rs |
napi-rs ColumnarStream, ColumnarChunk |
src/types.rs |
napi-rs SqlType, TableDefinition, CreateMode |
src/query_stats.rs |
Query statistics |
index.js |
Native binding loader + JS extensions (tagged templates, parameterized queries, event hooks, Symbol.asyncDispose, toJSON) |
index.d.ts |
Hand-written TypeScript declarations (full IntelliSense) |
pool.mjs |
ConnectionPool — pure JS connection pooling |
arrow.mjs |
Arrow convenience helpers (tableFromQuery, insertFromTable, etc.) |
Cargo.toml |
Rust crate config (cdylib, depends on hyperdb-api + hyperdb-api-core) |
package.json |
npm package config, build scripts, platform triples |
Prerequisites: Rust toolchain, Node.js >= 21, HYPERD_PATH set.
cd hyperdb-api-node
# Install JS dependencies (includes @napi-rs/cli)
npm install
# Build native addon (debug — fast compile, slow runtime)
npm run build:debug
# Build native addon (release — slow compile, fast runtime)
npm run build
# Run smoke tests
npm test
# Run benchmarks (build release first!)
npm run build && npm run benchmarkcargo build -p hyperdb-api-node --release— compiles the Rust crate to a.nodeshared librarynode scripts/copy-node.js release— copies the build artifact to the project root with the platform-specific name (e.g.,hyperdb-api-node.darwin-arm64.node)
- Each Rust struct in
src/*.rsuses#[napi]attribute macros to expose constructors, methods, and properties to JS. - Sync Rust → Async JS: Blocking Rust methods are wrapped with
tokio::task::spawn_blockingand returnPromiseto JavaScript. - Thread safety: Connections are wrapped in
Arc<Mutex<...>>for safe concurrent access from the JS event loop.
The native binding loader (index.js) is not just a loader — it adds significant functionality on top of the napi-rs exports:
- Parameterized queries (
executeQueryParams,executeCommandParams) —$1/$2placeholder substitution viaescapeParam() - Tagged template literals (
conn.sql\...`,conn.command`...``) — safe SQL interpolation - Query event hooks (
conn.on('query', ...)) — wrapsexecuteQuery/executeCommandwith timing Symbol.asyncDispose/Symbol.dispose— resource management forawait usingRowData.toJSON()— serialization with optional column namesQueryStream[Symbol.asyncIterator]—for await (const row of stream)supportcreateExtractTable()— Tableau Extract schema helper
When modifying connection behavior, check both src/connection.rs (Rust) and index.js (JS wrappers).
index.d.ts is hand-written, not auto-generated. It must be updated manually when:
- A new class or method is added in the Rust source
- A new JS extension is added in
index.js - Method signatures change
pool.mjs—ConnectionPoolwith configurable min/max, idle timeout, acquire timeout. Entirely in JS, wrapsConnection.arrow.mjs— Convenience wrappers aroundexecuteQueryToArrow()using theapache-arrowpeer dependency. Also entirely in JS.
- Smoke tests:
__test__/smoke.mjs— covers all major features (connection, queries, inserts, streams, pool, tagged templates, BigInt, dates, JSON, event hooks) - Benchmarks:
__test__/benchmark.mjs— insert and query performance with configurable row counts - Tests require
HYPERD_PATHto be set - Test artifacts go into
test_results/(gitignored)
Uses napi-rs platform packages for cross-platform prebuilt binaries:
| Platform | Package |
|---|---|
| macOS ARM64 | hyperdb-api-node-darwin-arm64 |
| Linux x64 (glibc) | hyperdb-api-node-linux-x64-gnu |
| Linux x64 (musl) | hyperdb-api-node-linux-x64-musl |
| Linux ARM64 | hyperdb-api-node-linux-arm64-gnu |
| Windows x64 | hyperdb-api-node-win32-x64-msvc |
macOS x64 (Intel) is currently disabled — macos-13 GHA runners are unreliable.
CI builds all enabled platforms on push. Publishing is driven by release-please.
- Implement in
src/connection.rswith#[napi]attribute - If it needs a JS wrapper (params, events, etc.), add to
index.js - Add TypeScript declaration to
index.d.ts - Add test case to
__test__/smoke.mjs
- Create
src/<name>.rs, add module tosrc/lib.rs - Use
#[napi]on the struct and its methods - Export from
index.js(it re-exports all nativeBinding properties) - Add TypeScript declarations to
index.d.ts - Add tests to
__test__/smoke.mjs
- Rust → JS: Reading conversions are in
src/result.rs(RowDatagetters) - JS → Rust: Writing conversions are in
src/inserter.rsandindex.js(escapeParam) - Update the type mapping tables in
README.mdif you change behavior
This package splits its documentation across two files:
- README.md — user-facing content: features, installation, Quick Start, API Reference, Arrow integration, benchmarks, examples. This is what users see on npmjs.com.
- DEVELOPMENT.md — contributor internals: architecture, module map, building from source, testing, publishing, adding new methods/extensions, design decisions, future enhancements.
When making changes:
- New user-facing API? Update the API Reference section in
README.md. - New build step, design decision, or contributor workflow? Update
DEVELOPMENT.md. - Implementation details for a single file? Prefer JSDoc comments in the source code over prose in
DEVELOPMENT.md. - Cross-cutting architecture or process? Put it in
DEVELOPMENT.mdor the top-leveldocs/folder.
Follow the Documentation Style Guide for JSDoc conventions, naming, and documentation structure.
index.d.tsis hand-written — always update it when changing the API surfaceindex.jsis more than a loader — it contains significant logic (params, templates, events, disposal)- Build release for benchmarks —
npm run build:debugproduces binaries 10x+ slower apache-arrowis an optional peer dependency —arrow.mjsgracefully handles its absence- Tests use
.mjs(ESM) — useimport/export, notrequirein test files - CJS entry point —
index.jsuses CommonJS (require/module.exports) for maximum compatibility