This document describes the code generation systems in Hyprnote that maintain type safety and automate boilerplate creation across the codebase. The system employs multiple generation strategies:
routeTree.gen.tsAGENTS.md listings via gen-agents.jsFor information about the plugin system architecture that uses these bindings, see Plugin System.
Hyprnote employs four primary code generation systems:
Type-safe IPC layer between Rust and TypeScript:
specta macros.gen.ts filesMDX processing with type safety:
@content-collections/vite plugin processes MDX filesallDocs and allTemplates generatedFile-based routing with type safety:
@tanstack/router-plugin scans src/routes directoryrouteTree.gen.ts with route definitionsAutomated documentation listings:
gen-agents.js script scans repository for AGENTS.md filesSources: apps/desktop/src-tauri/src/lib.rs191-199 Cargo.toml219-221 apps/web/vite.config.ts1-43 apps/web/scripts/gen-agents.js1-70
| Library | Purpose | Version |
|---|---|---|
specta | Core Rust type serialization to TypeScript | 2.0.0-rc.22 |
specta-typescript | TypeScript code generator | 0.0.9 |
tauri-specta | Tauri integration for specta | 2.0.0-rc.21 |
| Library | Purpose | Version |
|---|---|---|
@content-collections/core | Core MDX processing | 0.11.1 |
@content-collections/mdx | MDX compilation | 0.2.2 |
@content-collections/vite | Vite plugin integration | 0.2.7 |
| Library | Purpose | Version |
|---|---|---|
@tanstack/router-plugin | Router code generation | 1.139.3 |
@tanstack/react-router | Runtime router | 1.139.3 |
These libraries work together to provide compile-time type safety across Rust/TypeScript boundaries, content management, and routing.
Sources: Cargo.toml219-221 apps/web/package.json63-83 apps/desktop/package.json1-137
Type Information Extraction: Specta derives extract type information from Rust structs and enums at compile time using procedural macros.
Code Generation Trigger: Running tests with cargo test executes export functions that write TypeScript files.
Frontend Import: TypeScript code imports from generated files, getting full type safety and IDE support.
Sources: apps/desktop/src-tauri/src/lib.rs142-168 plugins/windows/src/lib.rs42-60
The main desktop application creates a tauri_specta::Builder to collect commands and configure code generation:
Sources: apps/desktop/src-tauri/src/lib.rs142-150
The builder is configured in make_specta_builder():
tauri_specta::collect_commands! macro to gather all annotated commandsErrorHandlingMode::Result to wrap errors in Result<T, E> typesCommands are defined in Rust with type safety annotations:
apps/desktop/src-tauri/src/commands.rs35-60
Key annotations:
#[tauri::command] - Marks function as Tauri command#[specta::specta] - Includes in type generationR: tauri::Runtime - Platform abstractionResult<T, String> - Type-safe error handlingCode generation is triggered by a test function:
apps/desktop/src-tauri/src/lib.rs152-168
Configuration details:
../src/types/tauri.gen.ts (relative to Cargo.toml)// @ts-nocheck commentNumber typeSources: apps/desktop/src-tauri/src/lib.rs35-168 apps/desktop/src-tauri/src/commands.rs35-60
The generated file provides type-safe command invocations:
apps/desktop/src/types/tauri.gen.ts9-34
Structure:
Result<T, E> union type for explicit error handlingGenerated types mirror Rust definitions:
apps/desktop/src/types/tauri.gen.ts46-47
Naming Convention: TypeScript types use same names as Rust structs
Nested Types: Complex types with nested structures are fully preserved
All commands return a discriminated union for error handling:
apps/desktop/src/types/tauri.gen.ts70-72
Usage Pattern:
Sources: apps/desktop/src/types/tauri.gen.ts1-108
Each plugin maintains its own generated bindings:
Plugin Isolation: Each plugin's types are generated independently
Package Export: Generated files are exported through plugin's package.json
Sources: plugins/windows/src/lib.rs42-103 plugins/windows/Cargo.toml1-41
The windows plugin demonstrates the pattern:
plugins/windows/src/lib.rs42-60
Key aspects:
.plugin_name("windows")tauri_specta::collect_events! for event typesplugin:windows:Plugin commands follow the same pattern with additional namespace:
plugins/windows/js/bindings.gen.ts9-66
Command Invocation: Uses plugin:windows|command_name pattern for namespacing
Type Safety: Same Result<T, E> pattern as main commands
Events get special handling with flexible listening patterns:
plugins/windows/js/bindings.gen.ts71-79
Event Object Structure:
listen(callback) - Subscribe to eventonce(callback) - Subscribe for single emissionemit(payload) - Emit event(window) - Window-specific event handlingSources: plugins/windows/src/lib.rs42-103 plugins/windows/js/bindings.gen.ts1-153
Events are defined with a macro for consistent derives:
plugins/windows/src/events.rs55-70
The common_event_derives! macro applies:
Debug - Debug printingserde::Serialize/Deserialize - JSON serializationClone - Value cloningspecta::Type - Type information for codegentauri_specta::Event - Event-specific metadataGenerated event utilities support multiple listening patterns:
Type Safety: Payload types are fully typed based on Rust event struct
Sources: plugins/windows/src/events.rs55-95 plugins/windows/js/bindings.gen.ts103-152
The generated event system integrates with TanStack Router for cross-window navigation:
apps/desktop/src/routes/__root.tsx51-72
Flow:
Navigate event with path and search parametersWindow operations use generated commands with discriminated unions:
apps/desktop/src/routes/app/onboarding/index.tsx71-87
Type Safety:
windowShow accepts AppWindow enumwindowDestroy type-checked at compile timeSources: apps/desktop/src/routes/__root.tsx51-72 apps/desktop/src/routes/app/onboarding/index.tsx71-87
Process:
cargo test to regenerate TypeScript bindingsGenerated files are checked into version control and validated in CI:
Validation: CI ensures generated files match current Rust code
Pattern Example: packages/obsidian/package.json13 shows validation in generate script
Sources: apps/desktop/src-tauri/src/lib.rs152-168 plugins/windows/src/lib.rs85-103
| Rust Type | TypeScript Type | Notes |
|---|---|---|
String | string | Direct mapping |
bool | boolean | Direct mapping |
i32, i64, u32, u64 | number | Configured via BigIntExportBehavior |
Option<T> | T | null | Nullable union type |
Vec<T> | T[] | Array type |
HashMap<K, V> | Partial<{ [key in K]: V }> | Object type |
struct | type or interface | Object type |
enum | Discriminated union | Tagged union |
Rust enums map to TypeScript discriminated unions:
plugins/windows/js/bindings.gen.ts87
Rust Definition:
Generated TypeScript:
Rust structs map to TypeScript object types:
apps/desktop/src/types/tauri.gen.ts46-47
Rust Definition (inferred from TS):
Sources: apps/desktop/src/types/tauri.gen.ts46-47 plugins/windows/js/bindings.gen.ts87-92
All commands return a Result<T, E> type for explicit error handling:
apps/desktop/src/types/tauri.gen.ts70-72
The specta builder configures error handling:
apps/desktop/src-tauri/src/lib.rs149
ErrorHandlingMode::Result:
Result<T, E>Example usage pattern:
Type Safety: TypeScript enforces checking result status before accessing data
Sources: apps/desktop/src-tauri/src/lib.rs142-150 apps/desktop/src/types/tauri.gen.ts70-72
Plugins define permissions that reference generated commands:
plugins/windows/permissions/default.toml1-11
Convention: Permission identifiers like allow-window-show correspond to command names
Capabilities reference plugin permissions:
apps/desktop/src-tauri/capabilities/default.json76-77
Type Safety: While not compile-time checked, permissions are validated at build time by Tauri
Sources: plugins/windows/permissions/default.toml1-11 apps/desktop/src-tauri/capabilities/default.json1-109
Each plugin's build.rs lists commands for permission generation:
Purpose: Generates permission schema from command list
Synchronization: Command list must match actual command implementations
The build process creates permission documentation:
plugins/windows/permissions/autogenerated/reference.md1-206
Auto-generated: This file is created during plugin build
Documentation: Provides reference for capability configuration
Sources: plugins/windows/build.rs1-13 plugins/windows/permissions/autogenerated/reference.md1-206
Content collections are configured in Vite:
The plugin processes MDX files and generates type-safe accessors.
MDX Compilation: Processes MDX with remark and rehype plugins for enhanced markdown
Type Generation: Creates TypeScript types for content structure
Hot Reload: Vite HMR updates content without full page reload
Sources: apps/web/vite.config.ts1-43 apps/web/package.json63-68
Content collections generate type-safe accessors:
Type Safety: Content structure validated at build time
IDE Support: Full autocomplete for content fields
Sources: apps/web/package.json65-67
TanStack Router generates route definitions from file structure:
The plugin scans the routes directory and generates type-safe routing code.
File-Based Routing: Route structure mirrors file system
Type Generation: Creates TypeScript types for routes and parameters
Hierarchical: Nested routes represented in tree structure
Sources: apps/desktop/src/routeTree.gen.ts1-315 apps/web/package.json39
Example generated route structure:
apps/desktop/src/routeTree.gen.ts25-85
Route Definitions:
FileRoutesByFullPath - Maps full paths to route typesFileRoutesByTo - Maps navigation targets to routesFileRoutesById - Maps route IDs to route typesType Safety: Navigation functions type-checked against route structure
Generated types enable type-safe navigation:
apps/desktop/src/routeTree.gen.ts87-123
Usage Pattern:
Sources: apps/desktop/src/routeTree.gen.ts1-315
The gen-agents.js script automates documentation index creation:
apps/web/scripts/gen-agents.js1-70
Process:
AGENTS.md filesAutomated Discovery: Finds all AGENTS.md files without manual listing
GitHub Integration: Links directly to source files for easy access
Build Integration: Runs via package.json script
Sources: apps/web/scripts/gen-agents.js1-70 apps/web/package.json11
Example generated output structure:
apps/web/content/docs/developers/10.agents.mdx1-32
Table Format:
Maintenance: No manual updates needed when adding/removing AGENTS.md files
Sources: apps/web/content/docs/developers/10.agents.mdx1-32 apps/web/scripts/gen-agents.js40-70
Commands:
Types:
Events:
cargo test for Rust bindings, npm run gen:* for other systems.gen.ts files, never hand-write bindingsSources: apps/desktop/src-tauri/src/lib.rs201-217 plugins/windows/src/events.rs53-68 apps/web/package.json11
The current configuration exports Rust u64 as TypeScript number:
apps/desktop/src-tauri/src/lib.rs162
Trade-off: JavaScript numbers lose precision beyond 2^53, but avoids BigInt complexity
Alternative: Can configure BigIntExportBehavior::BigInt if precision needed
All commands are async on the TypeScript side:
apps/desktop/src/types/tauri.gen.ts10
Reason: Tauri IPC is inherently asynchronous
Impact: Even synchronous Rust functions become async in TypeScript
Types must be serde-serializable to cross IPC boundary:
Restrictions:
Sources: apps/desktop/src-tauri/src/lib.rs162 apps/desktop/src/types/tauri.gen.ts10-17
Refresh this wiki
This wiki was recently refreshed. Please wait 7 days to refresh again.