Type-safe, auto-generated IPC communication for Electron apps. Define handlers once, get full TypeScript definitions and preload scripts automatically.
npm install ipc-router
pnpm add ipc-router
yarn add ipc-router// src/main/controllers/user.ts
import { ipcRouter } from 'ipc-router'
const userRouter = ipcRouter('user')
userRouter.handle('getProfile', async (event, userId: string): Promise<User> => {
return await database.users.findById(userId)
})
userRouter.on('logout', (event, userId: string) => {
console.log(`User ${userId} logged out`)
})
export default userRouter// src/main/index.ts
import { ipcApp } from 'ipc-router'
import userRouter from './controllers/user'
const ipc = ipcApp()
ipc.use(userRouter)# Add to package.json
{
"scripts": {
"preload:generate": "generate-preload"
}
}
# Run once
npm run preload:generate// src/preload/index.ts
import { contextBridge } from 'electron'
import { api } from './ipc-router'
contextBridge.exposeInMainWorld('api', api)// src/renderer/App.tsx
// Full type safety - autocomplete works!
const user = await window.api.user.getProfile('123')
window.api.user.logout('123')Create a config file to customize generation:
npx generate-preload initipc-router.config.cjs (CommonJS):
module.exports = {
controllersPattern: ['./**/main/**/*.ts', './**/main/**/*.js'],
excludePatterns: ['**/node_modules/**', '**/dist/**'],
outputDir: './src/preload',
}ipc-router.config.mjs (ESM):
export default {
controllersPattern: ['./**/main/**/*.ts', './**/main/**/*.js'],
excludePatterns: ['**/node_modules/**', '**/dist/**'],
outputDir: './src/preload',
}- Type-Safe - Full TypeScript definitions generated automatically
- Type Extraction - Intelligently extracts and handles all type annotations
- Multiple Arguments - Support for complex function signatures with multiple parameters
- External Types - Automatically imports types from external libraries
- Error Handling - Errors caught and re-thrown with proper context
- Zero Config - Works out of the box with sensible defaults
| Method | Description |
|---|---|
ipcRouter(prefix) |
Create a new router with optional prefix |
router.handle(channel, handler) |
Register two-way request handler |
router.on(channel, handler) |
Register one-way event handler |
ipcApp() |
Create app instance to register multiple routers |
Example:
const router = ipcRouter('auth')
// Two-way: renderer calls → waits for response
router.handle('login', async (event, creds: Credentials): Promise<User> => {
return await authenticate(creds)
})
// One-way: renderer sends → no response
router.on('logout', (event, userId: string) => {
cleanup(userId)
})# Generate preload scripts
npx generate-preload
# With verbose output
npx generate-preload --verbose
# Custom config
npx generate-preload --config ./my-config.js
# Create sample config
npx generate-preload init- Organize by feature - Group related handlers in separate controller files
- Type everything - Always specify parameter and return types
- Use shared types - Place common types in a
sharedfolder, not in controllers - Descriptive names - Use clear channel names like
getUserProfilenotget - Handle errors - Wrap operations in try-catch and return meaningful errors
Example structure:
src/
├── main/
│ └── controllers/
│ ├── auth.ts
│ ├── users.ts
│ └── files.ts
└── shared/
└── types.ts
# Install dependencies
pnpm install
# Tests
pnpm test
pnpm test:watch
pnpm test:coverage
# Build
pnpm build
pnpm dev- Add middleware
- Class-based controllers with decorators
- Runtime validation integration (Zod)
- Main-to-renderer bidirectional communication
MIT - See license for details.
Contributions welcome! Fork, create a feature branch, commit, and open a PR.