electrobun-rpc
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseElectrobun RPC System
Electrobun RPC 系统
Type-safe bidirectional communication between the Bun process and webview renderers. Uses WebSockets for transport with AES-GCM encryption. Two call types: (expects a response) and (fire-and-forget).
requestsmessagesBun 进程与 WebView 渲染器之间的类型安全双向通信。使用 WebSockets 作为传输层,并采用 AES-GCM 加密。包含两种调用类型:(需要响应)和 (无需等待响应)。
requestsmessagesSchema Definition (shared type)
Schema 定义(共享类型)
Define the schema in a shared file both sides import:
typescript
// src/shared/rpc-schema.ts
import type { ElectrobunRPCSchema, RPCSchema } from "electrobun/view";
// bun: what the BUN process handles (requests from renderer, messages from renderer)
// webview: what the WEBVIEW handles (requests from bun, messages from bun)
export type AppRPC = {
bun: RPCSchema<{
requests: {
getNotes: { args: {}; response: Note[] };
saveNote: { args: { id: string; title: string; content: string }; response: { success: boolean } };
deleteNote: { args: { id: string }; response: void };
};
messages: {
userIdleDetected: {};
};
}>;
webview: RPCSchema<{
requests: {
getSelectedText: { args: {}; response: string };
};
messages: {
menuAction: { action: string; role?: string };
noteUpdatedExternally: { id: string };
};
}>;
} & ElectrobunRPCSchema;在双方共同导入的共享文件中定义 schema:
typescript
// src/shared/rpc-schema.ts
import type { ElectrobunRPCSchema, RPCSchema } from "electrobun/view";
// bun: what the BUN process handles (requests from renderer, messages from renderer)
// webview: what the WEBVIEW handles (requests from bun, messages from bun)
export type AppRPC = {
bun: RPCSchema<{
requests: {
getNotes: { args: {}; response: Note[] };
saveNote: { args: { id: string; title: string; content: string }; response: { success: boolean } };
deleteNote: { args: { id: string }; response: void };
};
messages: {
userIdleDetected: {};
};
}>;
webview: RPCSchema<{
requests: {
getSelectedText: { args: {}; response: string };
};
messages: {
menuAction: { action: string; role?: string };
noteUpdatedExternally: { id: string };
};
}>;
} & ElectrobunRPCSchema;Bun Side — BrowserView.defineRPC
Bun 端 — BrowserView.defineRPC
typescript
import { BrowserView } from "electrobun/bun";
import type { AppRPC } from "../shared/rpc-schema";
const appRPC = BrowserView.defineRPC<AppRPC>({
maxRequestTime: 10000, // ms — set higher for file dialogs, heavy DB ops
handlers: {
requests: {
getNotes: async () => {
return await db.getAllNotes();
},
saveNote: async ({ id, title, content }) => {
await db.saveNote({ id, title, content });
return { success: true };
},
deleteNote: async ({ id }) => {
await db.deleteNote(id);
},
},
messages: {
userIdleDetected: () => {
console.log("User idle, saving state...");
},
},
},
});
// Pass rpc to BrowserView
const view = new BrowserView({ url: "...", rpc: appRPC });
// Send a message to renderer
view.rpc.send.menuAction({ action: "file-new" });
// Make a request to renderer
const selectedText = await view.rpc.request.getSelectedText({});typescript
import { BrowserView } from "electrobun/bun";
import type { AppRPC } from "../shared/rpc-schema";
const appRPC = BrowserView.defineRPC<AppRPC>({
maxRequestTime: 10000, // ms — set higher for file dialogs, heavy DB ops
handlers: {
requests: {
getNotes: async () => {
return await db.getAllNotes();
},
saveNote: async ({ id, title, content }) => {
await db.saveNote({ id, title, content });
return { success: true };
},
deleteNote: async ({ id }) => {
await db.deleteNote(id);
},
},
messages: {
userIdleDetected: () => {
console.log("User idle, saving state...");
},
},
},
});
// Pass rpc to BrowserView
const view = new BrowserView({ url: "...", rpc: appRPC });
// Send a message to renderer
view.rpc.send.menuAction({ action: "file-new" });
// Make a request to renderer
const selectedText = await view.rpc.request.getSelectedText({});Renderer Side — Electroview.defineRPC
渲染器端 — Electroview.defineRPC
typescript
// src/mainview/index.ts
import { Electroview } from "electrobun/view";
import type { AppRPC } from "../shared/rpc-schema";
const rpc = Electroview.defineRPC<AppRPC>({
maxRequestTime: 10000,
handlers: {
requests: {
getSelectedText: () => {
return window.getSelection()?.toString() ?? "";
},
},
messages: {
menuAction: ({ action, role }) => {
handleMenuAction(action ?? role ?? "unknown");
},
noteUpdatedExternally: ({ id }) => {
reloadNote(id);
},
},
},
});
// Make a request to bun
const notes = await rpc.request.getNotes({});
// Send a message to bun
rpc.send.userIdleDetected({});typescript
// src/mainview/index.ts
import { Electroview } from "electrobun/view";
import type { AppRPC } from "../shared/rpc-schema";
const rpc = Electroview.defineRPC<AppRPC>({
maxRequestTime: 10000,
handlers: {
requests: {
getSelectedText: () => {
return window.getSelection()?.toString() ?? "";
},
},
messages: {
menuAction: ({ action, role }) => {
handleMenuAction(action ?? role ?? "unknown");
},
noteUpdatedExternally: ({ id }) => {
reloadNote(id);
},
},
},
});
// Make a request to bun
const notes = await rpc.request.getNotes({});
// Send a message to bun
rpc.send.userIdleDetected({});Key Rules
关键规则
- : bidirectional, async, returns a value. Use for: data fetching, file I/O, native dialogs.
requests - : fire-and-forget, no return value. Use for: notifications, state updates, events.
messages - : always set explicitly. Default may be too low for:
maxRequestTime- File save dialogs: set ≥ 30000
- Database operations: set ≥ 10000
- Quick in-memory ops: 5000 is fine
- Type safety: the schema type is shared — import it on both sides. Never duplicate the type definition.
- Encryption: RPC uses AES-GCM. Keys are auto-generated per session. Don't bypass this.
- :双向、异步并返回一个值。适用于:数据获取、文件 I/O、原生对话框。
requests - :无需等待响应,不返回值。适用于:通知、状态更新、事件。
messages - :始终显式设置。以下场景的默认值可能过低:
maxRequestTime- 文件保存对话框:设置为 ≥ 30000
- 数据库操作:设置为 ≥ 10000
- 快速内存操作:设置为 5000 即可
- 类型安全:schema 类型由双方共享——两端都应导入该类型。切勿重复定义类型。
- 加密:RPC 使用 AES-GCM。密钥会为每个会话自动生成。请勿绕过此机制。
Common Gotchas
常见问题
- RPC not available yet: Wait for event before calling
dom-ready.view.rpc.request.* - maxRequestTime timeout: Error message is generic. If you see "RPC timeout", increase .
maxRequestTime - sandbox: true: Disables RPC entirely. Don't set sandbox on windows that need RPC.
- Schema mismatch: If bun and renderer import different schema types, calls silently fail. Use a single shared type file.
- Renderer not initialized: must be called before any
Electroview.defineRPCcalls.rpc.request.*
- RPC 尚不可用:调用 前,请等待
view.rpc.request.*事件。dom-ready - 超时:错误消息比较通用。如果看到“RPC timeout”,请增加
maxRequestTime。maxRequestTime - :会完全禁用 RPC。需要 RPC 的窗口不应设置 sandbox。
sandbox: true - Schema 不匹配:如果 bun 和渲染器导入的 schema 类型不同,调用会静默失败。请使用同一个共享类型文件。
- 渲染器尚未初始化:调用任何 前,必须先调用
rpc.request.*。Electroview.defineRPC