@isdk/ai-tool-electron
v0.1.2
Published
> ✨ **Electron-native IPC Transport for the `ToolFunc` Framework** > Build decoupled, type-safe, real-time Electron apps with RPC tools and Pub/Sub events over IPC.
Readme
@isdk/ai-tool-electron
✨ Electron-native IPC Transport for the
ToolFuncFramework Build decoupled, type-safe, real-time Electron apps with RPC tools and Pub/Sub events over IPC.
npm install @isdk/ai-tool-electronBuilt on @isdk/ai-tool — Define reusable, self-documenting functions.
🌟 Features
Designed to pair with @isdk/ai-tool. Define your business logic once as tools, then call them from the renderer like local methods —— no HTTP required.
- ✅ Zero network overhead - uses Electron IPC
- ✅ RPC Tools over IPC — Call server-defined functions from renderer
- ✅ Real-time Event Bus — Bidirectional Pub/Sub with auto session management
- ✅ Unified error model via @isdk/common-error
- ✅ AbortSignal support - cancel waiting on the client
- ✅ Safe Preload Bridge — Securely expose APIs via
contextBridge - ✅ Dynamic Namespaces — Run multiple isolated tool/event buses
🚀 Quick Start
1. Main Process (Server)
// main.ts
import {
ServerTools,
IpcServerToolTransport,
EventServer,
ElectronServerPubSubTransport,
} from '@isdk/ai-tool-electron';
// Register a tool
ServerTools.register({
name: 'getUser',
func: async ({ id }) => ({ id, name: 'Alice' }),
});
// Mount RPC
const serverTransport = new IpcServerToolTransport();
serverTransport.mount(ServerTools, 'my-app');
// Setup event bus
EventServer.setPubSubTransport(
new ElectronServerPubSubTransport('my-app-events')
);
EventServer.get().register();
await serverTransport.start(); // No port needed!2. Preload Script (Secure Bridge)
// preload.ts
import { contextBridge } from 'electron';
import {
backendEventable,
EventClient,
} from '@isdk/ai-tool';
import {
IpcClientToolTransport,
ElectronClientPubSubTransport,
} from '@isdk/ai-tool-electron';
contextBridge.exposeInMainWorld('toolBridge', {
async init() {
// Mount tools
const transport = new IpcClientToolTransport('my-app');
await transport.mount(ServerTools);
// Setup events
EventClient.setPubSubTransport(new ElectronClientPubSubTransport());
backendEventable(EventClient);
EventClient.get().setApiRoot('my-app-events').register();
return { ready: true };
},
invokeTool: (name, params, options) =>
ServerTools.get(name)?.run(params, options),
getEventClient: () => EventClient.get(),
});3. Renderer Process (Client)
// renderer.tsx
const { toolBridge } = window;
await toolBridge.init();
// ➡️ Call tool
const user = await toolBridge.invokeTool('getUser', { id: '123' });
console.log(user); // { id: '123', name: 'Alice' }
// 🔔 Listen to events
const ec = toolBridge.getEventClient();
ec.on('user-updated', data => console.log('Updated:', data));
await ec.subscribe('user-updated');
// 📤 Emit event to main process
ec.forwardEvent('local-event');
ec.emit('local-event', { action: 'clicked' });🔄 Architecture
graph LR
subgraph "Main Process"
A[ServerTools] --> B[IpcServer]
C[EventServer] --> D[PubSub Server]
B -->|ipcMain| E[(IPC Channel)]
D -->|ipcMain| E
end
subgraph "Renderer Process"
F[ClientTools] --> G[IpcClient]
H[EventClient] --> I[PubSub Client]
G -->|ipcRenderer| E
I -->|ipcRenderer| E
end⚙️ Advanced
Timeout & Cancellation
const ctrl = new AbortController();
setTimeout(() => ctrl.abort(), 5000);
try {
await tool.run(params, { signal: ctrl.signal, timeout: 10_000 });
} catch (err) {
if (err.name === 'AbortError') {
console.log('Cancelled or timed out');
}
}Handshake (Optional)
// Client
pubsub.connect('bus', {
waitForHandshake: true,
handshakeTimeout: 5000,
});
// Server auto-responds if client sends `sendHandshake: true`🧪 Testing
Run unit tests with mocked Electron IPC:
npm test # run once
npm run test:watch # dev mode
npm run coverage # generate reportMocks: test/mocks/electron.ts
📚 Docs
🤝 Contributing
We ❤️ contributions!
- Fork →
git clone - Create branch →
git checkout -b feat/your-feature - Commit →
git commit -m 'feat: add XYZ' - Push →
git push origin feat/your-feature - Open PR 🎉
Please ensure tests pass and types are clean.
📜 License
💡 Pro Tip: Use
EventServer.forward([...events])to auto-relay global events to all connected clients!
