@noxfly/noxus
Version:
Simulate lightweight HTTP-like requests between renderer and main process in Electron applications with MessagePort, with structured and modular design.
76 lines (63 loc) • 2.4 kB
text/typescript
/**
* @copyright 2025 NoxFly
* @license MIT
* @author NoxFly
*/
import { contextBridge, ipcRenderer } from 'electron/renderer';
import type { IPortRequester } from 'src/renderer-client';
export interface NoxusPreloadAPI extends IPortRequester {}
export interface NoxusPreloadOptions {
exposeAs?: string;
initMessageType?: string;
requestChannel?: string;
responseChannel?: string;
targetWindow?: Window;
}
const DEFAULT_EXPOSE_NAME = 'noxus';
const DEFAULT_INIT_EVENT = 'init-port';
const DEFAULT_REQUEST_CHANNEL = 'gimme-my-port';
const DEFAULT_RESPONSE_CHANNEL = 'port';
/**
* Exposes a minimal bridge in the isolated preload context so renderer processes
* can request the two MessagePorts required by Noxus. The bridge forwards both
* request/response and socket ports to the renderer via window.postMessage.
*/
export function exposeNoxusBridge(options: NoxusPreloadOptions = {}): NoxusPreloadAPI {
const {
exposeAs = DEFAULT_EXPOSE_NAME,
initMessageType = DEFAULT_INIT_EVENT,
requestChannel = DEFAULT_REQUEST_CHANNEL,
responseChannel = DEFAULT_RESPONSE_CHANNEL,
targetWindow = window,
} = options;
const api: NoxusPreloadAPI = {
requestPort: () => {
ipcRenderer.send(requestChannel);
ipcRenderer.once(responseChannel, (event, message: { senderId: number }) => {
const ports = (event.ports ?? []).filter((port): port is MessagePort => port !== undefined);
if(ports.length === 0) {
console.error('[Noxus] No MessagePort received from main process.');
return;
}
for(const port of ports) {
try {
port.start();
}
catch(error) {
console.error('[Noxus] Failed to start MessagePort.', error);
}
}
targetWindow.postMessage(
{
type: initMessageType,
senderId: message?.senderId,
},
'*',
ports,
);
});
},
};
contextBridge.exposeInMainWorld(exposeAs, api);
return api;
}