/* eslint-disable @typescript-eslint/no-var-requires */ // NOTE: we will generate preload types from this file import { ipcRenderer } from 'electron'; import type { MainIPCEventMap, MainIPCHandlerMap } from '../../constraints'; type WithoutFirstParameter = T extends (_: any, ...args: infer P) => infer R ? (...args: P) => R : T; type HandlersMap = { [K in keyof MainIPCHandlerMap[N]]: WithoutFirstParameter< MainIPCHandlerMap[N][K] >; }; type PreloadHandlers = { [N in keyof MainIPCHandlerMap]: HandlersMap; }; type MainExposedMeta = { handlers: [namespace: string, handlerNames: string[]][]; events: [namespace: string, eventNames: string[]][]; }; // main handlers that can be invoked from the renderer process const apis: PreloadHandlers = (() => { // the following were generated by the build script // 1. bundle extra main/src/expose.ts entry // 2. use generate-main-exposed-meta.mjs to generate exposed-meta.js in dist // // we cannot directly import main/src/handlers.ts because it will be bundled into the preload bundle // eslint-disable-next-line @typescript-eslint/no-var-requires const { handlers: handlersMeta, }: MainExposedMeta = require('../main/exposed-meta'); const all = handlersMeta.map(([namespace, functionNames]) => { const namespaceApis = functionNames.map(name => { const channel = `${namespace}:${name}`; return [ name, (...args: any[]) => { return ipcRenderer.invoke(channel, ...args); }, ]; }); return [namespace, Object.fromEntries(namespaceApis)]; }); return Object.fromEntries(all); })(); // main events that can be listened to from the renderer process const events: MainIPCEventMap = (() => { const { events: eventsMeta, }: MainExposedMeta = require('../main/exposed-meta'); // NOTE: ui may try to listen to a lot of the same events, so we increase the limit... ipcRenderer.setMaxListeners(100); const all = eventsMeta.map(([namespace, eventNames]) => { const namespaceEvents = eventNames.map(name => { const channel = `${namespace}:${name}`; return [ name, (callback: (...args: any[]) => void) => { const fn: ( event: Electron.IpcRendererEvent, ...args: any[] ) => void = (_, ...args) => { callback(...args); }; ipcRenderer.on(channel, fn); return () => { ipcRenderer.off(channel, fn); }; }, ]; }); return [namespace, Object.fromEntries(namespaceEvents)]; }); return Object.fromEntries(all); })(); const appInfo = { electron: true, }; export { apis, appInfo, events };