/** * RPC singleton — breaks the circular import chain. * * main.ts creates the Electroview and RPC, then sets it here. * All other modules import from this file instead of main.ts. * * Fix #17: Typed RPC interface instead of `any`. */ import type { PtyRPCSchema, PtyRPCRequests, PtyRPCMessages } from '../shared/pty-rpc-schema.ts'; // ── Typed RPC interface ────────────────────────────────────────────────────── type RequestFn = (params: PtyRPCRequests[K]['params']) => Promise; type MessagePayload = PtyRPCMessages[K]; type MessageListener = (payload: MessagePayload) => void; export interface AppRpcHandle { request: { [K in keyof PtyRPCRequests]: RequestFn }; addMessageListener: (event: K, handler: MessageListener) => void; removeMessageListener?: (event: K, handler: MessageListener) => void; } // ── Internal holder ────────────────────────────────────────────────────────── let _rpc: AppRpcHandle | null = null; /** Called once from main.ts after Electroview.defineRPC(). */ export function setAppRpc(rpc: AppRpcHandle): void { _rpc = rpc; } /** * The app-wide RPC handle. * Safe to call after main.ts has executed (Svelte components mount after). */ export const appRpc: AppRpcHandle = new Proxy({} as AppRpcHandle, { get(_target, prop) { if (!_rpc) { throw new Error(`[rpc] accessed before init — property "${String(prop)}"`); } return (_rpc as Record)[prop]; }, });