Database
Plugin-scoped SQLite database. Each plugin id gets its own file under HarborClient userData (plugin-databases/{pluginId}.sqlite). Requires the database permission.
Use hc.database when you need indexed queries, relational data, or large structured stores. Keep small settings in hc.storage; the two APIs share no tables and neither can access HarborClient collections or other plugins' data.
get, all, and run accept single-statement parameterized SQL (? placeholders). Use exec for migration scripts (multi-statement DDL). Use transaction for atomic multi-step writes.
Main entry
The main entry uses the same database API. Calls route through the Electron main process, which opens one isolated file per plugin id. Use this from HTTP hooks when you need relational persistence without a renderer bridge.
hc.database.all(sql, params?)
Available since v2.0.0
Signature:<T = Record<string, unknown>>(sql: string, params?: unknown[]) => Promise<T[]>
Returns all matching rows.
hc.database.exec(sql)
Available since v2.0.0
Signature:(sql: string) => Promise<void>
Executes a multi-statement SQL script (typically migrations). Rejects scripts containing ATTACH, DETACH, or load_extension.
await hc.database.exec(`
CREATE TABLE IF NOT EXISTS events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
request_id INTEGER NOT NULL,
status INTEGER NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX IF NOT EXISTS idx_events_request_id ON events(request_id);
`);hc.database.get(sql, params?)
Available since v2.0.0
Signature:<T = Record<string, unknown>>(sql: string, params?: unknown[]) => Promise<T | undefined>
Returns the first row, or undefined when no row matches.
const row = await hc.database.get<{ count: number }>(
'SELECT COUNT(*) AS count FROM events WHERE request_id = ?',
[requestId]
);hc.database.run(sql, params?)
Available since v2.0.0
Signature:(sql: string, params?: unknown[]) => Promise<PluginRunResult>
Runs an INSERT, UPDATE, or DELETE statement. Returns { changes, lastInsertRowid }.
hc.database.transaction(fn)
Available since v2.7.0
Signature:<T>(fn: (tx: PluginDatabaseTx) => Promise<T>) => Promise<T>
Runs fn inside an exclusive transaction. The tx object exposes get, all, and run bound to the same transaction.
Plugin database files are included in HarborClient .hcb backups and removed when the plugin is uninstalled.
await hc.database.transaction(async (tx) => {
await tx.run('INSERT INTO outbox (payload) VALUES (?)', [JSON.stringify(body)]);
await tx.run('UPDATE counters SET value = value + 1 WHERE name = ?', ['sent']);
});