Extension Development
Irodori Table treats extensions as a product surface. The extension system starts with TypeScript because that is the fastest path for commands, UI integrations, themes, result-grid tools, and SQL dialect metadata. Rust/Wasm remains available for high-performance drivers, parsers, renderers, and formatters.
Current Implementation
- Manifest schema:
extension.schema.json, for files namedirodori.extension.json. - Rust source of truth:
irodori-extension. - Generated SDK contracts:
packages/extension-sdk/src/generated/irodori-extension-api.ts. - TypeScript SDK:
packages/extension-sdk/src/index.ts. - Local dev CLI:
packages/extension-sdk/bin/irodori-extension-dev.mjs. - Templates:
packages/extension-sdk/templates/typescript-basicandpackages/extension-sdk/templates/wasm-sql-dialect. - Native connector examples:
irodori-extension-duckdbandirodori-extension-memgraph. - Native connector host:
irodori-tableincludes the dynamic-library extension host, manifest/integrity checks, and marketplace catalog plumbing. The shared native ABI helper/macro lives inirodori-connector-abi.
Manifest
Extensions declare a strict irodori.extension.json manifest. The schema rejects
unknown top-level and contribution fields so the host can safely validate packages
before loading them.
{
"$schema": "../../extension.schema.json",
"manifestVersion": 1,
"id": "example.quick-export",
"name": "Quick Export",
"version": "0.1.0",
"license": "MIT OR 0BSD",
"apiVersion": "0.1",
"runtime": "typescript",
"entry": "dist/main.js",
"permissions": ["commands", "queryResults:read", "resultRenderers"],
"contributes": {
"commands": [
{
"id": "quickExport.copyAsMarkdown",
"title": "Copy Result as Markdown Table",
"category": "Result Grid",
"enablement": "resultGridFocus"
}
],
"resultGridActions": [
{
"id": "quickExport.copyMarkdownAction",
"title": "Copy as Markdown",
"command": "quickExport.copyAsMarkdown",
"when": "resultGridFocus"
}
]
}
}
Core manifest fields:
manifestVersion: currently1.apiVersion: currently0.1.runtime:typescript,javascript,wasm, ornative.permissions: explicit capability scopes such ascommands,queryResults:read,themes,sqlDialects,native, andwasm.contributes: declarative commands, keybindings, result-grid actions/renderers, themes, and SQL dialects.capabilities: Wasm and native module declarations.dev: watch paths, fake database fixtures, and log file configuration for local development.
Validate all checked-in extension templates and examples from the repository root:
make extension-manifests
The same guard runs in CI and checks required fields, unknown keys, safe relative paths, permission/contribution consistency, template/example licenses, and manifest sample fixtures.
Type Generation
The extension SDK uses the same typeship pattern as the desktop app.
cargo test -p irodori-extension export_typescript_bindings
The Rust crate owns the serde/TS contracts for:
- manifest and contribution data;
- permission scopes and permission inspection;
- result-grid columns, rows, selections, and snapshots;
- theme definitions and token color rules;
- SQL dialect definitions, keywords, snippets, and formatter config;
- Wasm/native module capability metadata;
- local development fixtures and logs.
The generated file is committed. In CI, the same test runs in check mode and fails if the generated SDK types drift from Rust.
TypeScript SDK
The SDK exposes generated contracts plus host-facing interfaces:
commands.registerCommandandcommands.executeCommand;keybindings.registerKeybinding;resultGrid.getActiveSnapshot,resultGrid.getSelection,resultGrid.registerAction, andresultGrid.copyText;themes.registerTheme;sqlDialects.registerDialect;permissions.has,permissions.require, andpermissions.inspect;- structured extension logging.
Extensions implement:
import type { ExtensionContext } from "@irodori-table/extension-sdk";
export async function activate(context: ExtensionContext): Promise<void> {
context.subscriptions.push(
context.commands.registerCommand("example.hello", async () => {
context.log.info("hello from an extension");
}),
);
}
Local Development
The local dev CLI reads a manifest, inspects declared permissions, loads fake database fixtures, writes JSON-line logs, and watches declared files for reload requests.
node packages/extension-sdk/bin/irodori-extension-dev.mjs packages/extension-sdk/templates/typescript-basic --once
The --once mode is useful for CI and smoke checks. Without it, the command stays
running and reports reload requests when watched paths change.
Runtime Safety Rules
- Extensions must declare permissions before using privileged APIs.
- Query text, query results, schema metadata, file access, native code, and Wasm modules are sensitive.
- Secrets are never exposed directly; extension APIs should receive handles or scoped operations.
- Native modules require platform metadata and should include
sha256before marketplace distribution. - Wasm modules must declare an ABI string. Current templates use
irodori-sql-dialect-v0while the host ABI is still stabilizing.
Next Host Work
- Wire manifest validation into the desktop extension loader.
- Implement the real desktop extension host behind the SDK interfaces.
- Add package archive verification and install/uninstall flows.
- Surface logs, reload state, and permission inspection in a developer panel.
- Add runtime validation for extension-provided theme, dialect, and renderer data.