TypeScript Bindings with tsify
This document describes the implementation of automatic TypeScript binding generation from Rust types using the tsify crate.
Overview
We have implemented a comprehensive TypeScript bindings system that automatically generates TypeScript definitions from Rust structs and enums. This eliminates manual type definitions and ensures type safety between the Rust backend and TypeScript frontend.
Implementation Details
1. Added tsify Dependencies
Core Crates with TypeScript Support:
crates/terraphim_config- Configuration typescrates/terraphim_types- Core domain typescrates/terraphim_automata- Automata and path typesdesktop/src-tauri- Tauri command response types
Cargo.toml Updates:
# In each crate
tsify = { version = "0.4", features = ["js"], optional = true }
wasm-bindgen = { version = "0.2", optional = true }
[features]
typescript = ["tsify", "wasm-bindgen"]2. Added tsify Derives to Rust Types
Configuration Types (terraphim_config):
ServiceType- Ripgrep vs Atomic service selectionHaystack- Individual document collection with service and parametersKnowledgeGraph- Knowledge graph configurationKnowledgeGraphLocal- Local KG configurationRole- User role with settings and haystacksConfig- Complete application configurationConfigId- Configuration type identifier
Core Domain Types (terraphim_types):
RoleName- Role name with normalizationNormalizedTermValue- Normalized search termsDocument- Document representationSearchQuery- Search request structureRelevanceFunction- Scoring algorithm selectionKnowledgeGraphInputType- Input format types
Automata Types (terraphim_automata):
AutomataPath- Local vs Remote automata file paths
Command Response Types (desktop/src-tauri/cmd.rs):
Status- Success/error statusConfigResponse- Configuration API responseSearchResponse- Search API responseDocumentResponse- Document API responseInitialSettings- Application startup settings
3. Automatic Binding Generation System
Generation Binary (desktop/src-tauri/src/bin/generate-bindings.rs):
use generate_typescript_bindings;
Generation Logic (desktop/src-tauri/src/bindings.rs):
- Uses tsify
DECLconstants to extract TypeScript definitions - Organizes types by category (Core, Configuration, Command Response)
- Writes to
desktop/src/lib/generated/types.ts - Includes header with regeneration instructions
4. Generated TypeScript Types
Output Location: desktop/src/lib/generated/types.ts
Key Generated Types:
// Service and configuration types
export type ServiceType = "Ripgrep" | "Atomic";
export type ConfigId = "Server" | "Desktop" | "Embedded";
export type RelevanceFunction = "terraphim-graph" | "title-scorer";
// Haystack with full feature support
export interface Haystack {
location: string;
service: ServiceType;
read_only?: boolean;
atomic_server_secret?: string | undefined;
extra_parameters?: Map<string, string>;
}
// Complete configuration structure
export interface Config {
id: ConfigId;
global_shortcut: string;
roles: AHashMap<RoleName, Role>;
default_role: RoleName;
selected_role: RoleName;
}
// API response types
export interface ConfigResponse {
status: Status;
config: Config;
}5. Frontend Integration
ConfigWizard.svelte Updates:
- Replaced manual type definitions with generated imports
- Added type safety for service selection
- Proper support for RelevanceFunction values ("title-scorer" vs "terraphim-graph")
- Full compatibility with new haystack structure
Import Pattern:
import type {
Config,
Role,
Haystack,
ServiceType,
ConfigId,
RelevanceFunction,
KnowledgeGraphInputType
} from "./generated/types";Benefits Achieved
β Type Safety
- Zero Type Mismatches: Frontend automatically stays in sync with backend
- Compile-Time Verification: TypeScript catches type errors immediately
- IDE Autocomplete: Full IntelliSense support for all Rust-defined types
β Maintenance Efficiency
- Single Source of Truth: Types defined once in Rust, used everywhere
- Automatic Updates: Changes to Rust types automatically propagate to frontend
- No Manual Sync: Eliminates handcrafted TypeScript definitions
β Developer Experience
- Consistent Naming: Rust conventions automatically translated to TypeScript
- Documentation: Type comments from Rust appear in TypeScript
- Refactoring Safety: Changes to Rust types cause TypeScript compilation errors if incompatible
β Feature Completeness
- Full Haystack Support: Service types, extra parameters, atomic secrets
- Configuration Wizard: Complete UI support for all configuration options
- API Compatibility: Perfect alignment between Tauri commands and frontend types
Usage Instructions
Regenerating Bindings
When Rust types change, regenerate TypeScript bindings:
Adding New Types
- Add tsify derive to Rust type:
- Add to generation script in
bindings.rs:
all_bindings.push_str;- Regenerate bindings:
- Import in frontend:
import type { NewType } from "./generated/types";Handling External Types
For types from external crates (like AHashMap), add type aliases:
// In generated/types.ts
export type AHashMap<K, V> = Record<string, V>;
export type Value = any;Build Integration
The bindings generation is integrated into the development workflow:
- Development: Run
cargo run --bin generate-bindingswhen types change - CI/CD: Can be automated to ensure frontend stays current
- Frontend Build: TypeScript compilation validates all generated types
Testing
The implementation is validated by:
- β Backend Compilation: All Rust code compiles with tsify features
- β Frontend Compilation: TypeScript build succeeds with generated types
- β ConfigWizard Integration: UI properly uses all new type features
- β Type Safety: No manual type casting required in frontend
Future Enhancements
- Automatic Regeneration: Watch Rust files and auto-regenerate on changes
- Documentation Generation: Extract Rust doc comments to TypeScript JSDoc
- Validation: Add runtime type validation for API boundaries
- Optimization: Tree-shake unused types for smaller bundles
Conclusion
The tsify implementation provides a robust, maintainable solution for TypeScript bindings that:
- Eliminates manual type maintenance
- Ensures perfect type safety
- Supports all configuration features
- Integrates seamlessly with existing workflow
This foundation enables confident frontend development with guaranteed backend compatibility.