refactor: deprecate invokers - auto proxying apis - strict types (#924)
* refactor: deprecate invokers * refactor: define routes and auto proxying routes * refactor: declare types for APIs, avoid making dynamic calls to any functions from the web * chore: deprecate route handling from preload script * refactor: deprecate unused apis
This commit is contained in:
parent
df977143ec
commit
c4d8defe94
100
core/src/api/index.ts
Normal file
100
core/src/api/index.ts
Normal file
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* App Route APIs
|
||||
* @description Enum of all the routes exposed by the app
|
||||
*/
|
||||
export enum AppRoute {
|
||||
setNativeThemeLight = 'setNativeThemeLight',
|
||||
setNativeThemeDark = 'setNativeThemeDark',
|
||||
setNativeThemeSystem = 'setNativeThemeSystem',
|
||||
appDataPath = 'appDataPath',
|
||||
appVersion = 'appVersion',
|
||||
getResourcePath = 'getResourcePath',
|
||||
openExternalUrl = 'openExternalUrl',
|
||||
openAppDirectory = 'openAppDirectory',
|
||||
openFileExplore = 'openFileExplorer',
|
||||
relaunch = 'relaunch',
|
||||
}
|
||||
|
||||
export enum AppEvent {
|
||||
onAppUpdateDownloadUpdate = 'onAppUpdateDownloadUpdate',
|
||||
onAppUpdateDownloadError = 'onAppUpdateDownloadError',
|
||||
onAppUpdateDownloadSuccess = 'onAppUpdateDownloadSuccess',
|
||||
}
|
||||
|
||||
export enum DownloadRoute {
|
||||
abortDownload = 'abortDownload',
|
||||
downloadFile = 'downloadFile',
|
||||
pauseDownload = 'pauseDownload',
|
||||
resumeDownload = 'resumeDownload',
|
||||
}
|
||||
|
||||
export enum DownloadEvent {
|
||||
onFileDownloadUpdate = 'onFileDownloadUpdate',
|
||||
onFileDownloadError = 'onFileDownloadError',
|
||||
onFileDownloadSuccess = 'onFileDownloadSuccess',
|
||||
}
|
||||
|
||||
export enum ExtensionRoute {
|
||||
baseExtensions = 'baseExtensions',
|
||||
getActiveExtensions = 'getActiveExtensions',
|
||||
installExtension = 'installExtension',
|
||||
invokeExtensionFunc = 'invokeExtensionFunc',
|
||||
updateExtension = 'updateExtension',
|
||||
uninstallExtension = 'uninstallExtension',
|
||||
}
|
||||
export enum FileSystemRoute {
|
||||
appendFile = 'appendFile',
|
||||
copyFile = 'copyFile',
|
||||
deleteFile = 'deleteFile',
|
||||
exists = 'exists',
|
||||
getResourcePath = 'getResourcePath',
|
||||
getUserSpace = 'getUserSpace',
|
||||
isDirectory = 'isDirectory',
|
||||
listFiles = 'listFiles',
|
||||
mkdir = 'mkdir',
|
||||
readFile = 'readFile',
|
||||
readLineByLine = 'readLineByLine',
|
||||
rmdir = 'rmdir',
|
||||
writeFile = 'writeFile',
|
||||
}
|
||||
|
||||
export type ApiFunction = (...args: any[]) => any
|
||||
|
||||
export type AppRouteFunctions = {
|
||||
[K in AppRoute]: ApiFunction
|
||||
}
|
||||
|
||||
export type AppEventFunctions = {
|
||||
[K in AppEvent]: ApiFunction
|
||||
}
|
||||
|
||||
export type DownloadRouteFunctions = {
|
||||
[K in DownloadRoute]: ApiFunction
|
||||
}
|
||||
|
||||
export type DownloadEventFunctions = {
|
||||
[K in DownloadEvent]: ApiFunction
|
||||
}
|
||||
|
||||
export type ExtensionRouteFunctions = {
|
||||
[K in ExtensionRoute]: ApiFunction
|
||||
}
|
||||
|
||||
export type FileSystemRouteFunctions = {
|
||||
[K in FileSystemRoute]: ApiFunction
|
||||
}
|
||||
|
||||
export type APIFunctions = AppRouteFunctions &
|
||||
AppEventFunctions &
|
||||
DownloadRouteFunctions &
|
||||
DownloadEventFunctions &
|
||||
ExtensionRouteFunctions &
|
||||
FileSystemRouteFunctions
|
||||
|
||||
export const APIRoutes = [
|
||||
...Object.values(AppRoute),
|
||||
...Object.values(DownloadRoute),
|
||||
...Object.values(ExtensionRoute),
|
||||
...Object.values(FileSystemRoute),
|
||||
]
|
||||
export const APIEvents = [...Object.values(AppEvent), ...Object.values(DownloadEvent)]
|
||||
@ -30,13 +30,6 @@ const downloadFile: (url: string, fileName: string) => Promise<any> = (url, file
|
||||
const abortDownload: (fileName: string) => Promise<any> = (fileName) =>
|
||||
global.core.api?.abortDownload(fileName)
|
||||
|
||||
/**
|
||||
* Retrieves the path to the app data directory using the `coreAPI` object.
|
||||
* If the `coreAPI` object is not available, the function returns `undefined`.
|
||||
* @returns A Promise that resolves with the path to the app data directory, or `undefined` if the `coreAPI` object is not available.
|
||||
*/
|
||||
const appDataPath: () => Promise<any> = () => global.core.api?.appDataPath()
|
||||
|
||||
/**
|
||||
* Gets the user space path.
|
||||
* @returns {Promise<any>} A Promise that resolves with the user space path.
|
||||
@ -70,7 +63,6 @@ export {
|
||||
executeOnMain,
|
||||
downloadFile,
|
||||
abortDownload,
|
||||
appDataPath,
|
||||
getUserSpace,
|
||||
openFileExplorer,
|
||||
getResourcePath,
|
||||
|
||||
@ -2,34 +2,39 @@
|
||||
* Export all types.
|
||||
* @module
|
||||
*/
|
||||
export * from "./types/index";
|
||||
export * from './types/index'
|
||||
|
||||
/**
|
||||
* Export all routes
|
||||
*/
|
||||
export * from './api'
|
||||
|
||||
/**
|
||||
* Export Core module
|
||||
* @module
|
||||
*/
|
||||
export * from "./core";
|
||||
export * from './core'
|
||||
|
||||
/**
|
||||
* Export Event module.
|
||||
* @module
|
||||
*/
|
||||
export * from "./events";
|
||||
export * from './events'
|
||||
|
||||
/**
|
||||
* Export Filesystem module.
|
||||
* @module
|
||||
*/
|
||||
export * from "./fs";
|
||||
export * from './fs'
|
||||
|
||||
/**
|
||||
* Export Extension module.
|
||||
* @module
|
||||
*/
|
||||
export * from "./extension";
|
||||
export * from './extension'
|
||||
|
||||
/**
|
||||
* Export all base extensions.
|
||||
* @module
|
||||
*/
|
||||
export * from "./extensions/index";
|
||||
export * from './extensions/index'
|
||||
|
||||
@ -1,18 +1,35 @@
|
||||
import { app, ipcMain, shell } from 'electron'
|
||||
import { app, ipcMain, shell, nativeTheme } from 'electron'
|
||||
import { ModuleManager } from './../managers/module'
|
||||
import { join } from 'path'
|
||||
import { ExtensionManager } from './../managers/extension'
|
||||
import { WindowManager } from './../managers/window'
|
||||
import { userSpacePath } from './../utils/path'
|
||||
import { AppRoute } from '@janhq/core'
|
||||
import { getResourcePath } from './../utils/path'
|
||||
|
||||
export function handleAppIPCs() {
|
||||
/**
|
||||
* Retrieves the path to the app data directory using the `coreAPI` object.
|
||||
* If the `coreAPI` object is not available, the function returns `undefined`.
|
||||
* @returns A Promise that resolves with the path to the app data directory, or `undefined` if the `coreAPI` object is not available.
|
||||
* Handles the "setNativeThemeLight" IPC message by setting the native theme source to "light".
|
||||
* This will change the appearance of the app to the light theme.
|
||||
*/
|
||||
ipcMain.handle('appDataPath', async (_event) => {
|
||||
return app.getPath('userData')
|
||||
ipcMain.handle(AppRoute.setNativeThemeLight, () => {
|
||||
nativeTheme.themeSource = 'light'
|
||||
})
|
||||
|
||||
/**
|
||||
* Handles the "setNativeThemeDark" IPC message by setting the native theme source to "dark".
|
||||
* This will change the appearance of the app to the dark theme.
|
||||
*/
|
||||
ipcMain.handle(AppRoute.setNativeThemeDark, () => {
|
||||
nativeTheme.themeSource = 'dark'
|
||||
})
|
||||
|
||||
/**
|
||||
* Handles the "setNativeThemeSystem" IPC message by setting the native theme source to "system".
|
||||
* This will change the appearance of the app to match the system's current theme.
|
||||
*/
|
||||
ipcMain.handle(AppRoute.setNativeThemeSystem, () => {
|
||||
nativeTheme.themeSource = 'system'
|
||||
})
|
||||
|
||||
/**
|
||||
@ -20,7 +37,7 @@ export function handleAppIPCs() {
|
||||
* @param _event - The IPC event object.
|
||||
* @returns The version of the app.
|
||||
*/
|
||||
ipcMain.handle('appVersion', async (_event) => {
|
||||
ipcMain.handle(AppRoute.appVersion, async (_event) => {
|
||||
return app.getVersion()
|
||||
})
|
||||
|
||||
@ -29,16 +46,20 @@ export function handleAppIPCs() {
|
||||
* The `shell.openPath` method is used to open the directory in the user's default file explorer.
|
||||
* @param _event - The IPC event object.
|
||||
*/
|
||||
ipcMain.handle('openAppDirectory', async (_event) => {
|
||||
ipcMain.handle(AppRoute.openAppDirectory, async (_event) => {
|
||||
shell.openPath(userSpacePath)
|
||||
})
|
||||
|
||||
ipcMain.handle(AppRoute.getResourcePath, async (_event) => {
|
||||
return getResourcePath()
|
||||
})
|
||||
|
||||
/**
|
||||
* Opens a URL in the user's default browser.
|
||||
* @param _event - The IPC event object.
|
||||
* @param url - The URL to open.
|
||||
*/
|
||||
ipcMain.handle('openExternalUrl', async (_event, url) => {
|
||||
ipcMain.handle(AppRoute.openExternalUrl, async (_event, url) => {
|
||||
shell.openExternal(url)
|
||||
})
|
||||
|
||||
@ -47,7 +68,7 @@ export function handleAppIPCs() {
|
||||
* @param _event - The IPC event object.
|
||||
* @param url - The URL to reload.
|
||||
*/
|
||||
ipcMain.handle('relaunch', async (_event, url) => {
|
||||
ipcMain.handle(AppRoute.relaunch, async (_event, url) => {
|
||||
ModuleManager.instance.clearImportedModules()
|
||||
|
||||
if (app.isPackaged) {
|
||||
@ -56,9 +77,7 @@ export function handleAppIPCs() {
|
||||
} else {
|
||||
for (const modulePath in ModuleManager.instance.requiredModules) {
|
||||
delete require.cache[
|
||||
require.resolve(
|
||||
join(userSpacePath, 'extensions', modulePath)
|
||||
)
|
||||
require.resolve(join(userSpacePath, 'extensions', modulePath))
|
||||
]
|
||||
}
|
||||
ExtensionManager.instance.setupExtensions()
|
||||
|
||||
@ -4,7 +4,7 @@ import { resolve, join } from 'path'
|
||||
import { WindowManager } from './../managers/window'
|
||||
import request from 'request'
|
||||
import { createWriteStream } from 'fs'
|
||||
import { getResourcePath } from './../utils/path'
|
||||
import { DownloadEvent, DownloadRoute } from '@janhq/core'
|
||||
const progress = require('request-progress')
|
||||
|
||||
export function handleDownloaderIPCs() {
|
||||
@ -13,7 +13,7 @@ export function handleDownloaderIPCs() {
|
||||
* @param _event - The IPC event object.
|
||||
* @param fileName - The name of the file being downloaded.
|
||||
*/
|
||||
ipcMain.handle('pauseDownload', async (_event, fileName) => {
|
||||
ipcMain.handle(DownloadRoute.pauseDownload, async (_event, fileName) => {
|
||||
DownloadManager.instance.networkRequests[fileName]?.pause()
|
||||
})
|
||||
|
||||
@ -22,7 +22,7 @@ export function handleDownloaderIPCs() {
|
||||
* @param _event - The IPC event object.
|
||||
* @param fileName - The name of the file being downloaded.
|
||||
*/
|
||||
ipcMain.handle('resumeDownload', async (_event, fileName) => {
|
||||
ipcMain.handle(DownloadRoute.resumeDownload, async (_event, fileName) => {
|
||||
DownloadManager.instance.networkRequests[fileName]?.resume()
|
||||
})
|
||||
|
||||
@ -32,23 +32,19 @@ export function handleDownloaderIPCs() {
|
||||
* @param _event - The IPC event object.
|
||||
* @param fileName - The name of the file being downloaded.
|
||||
*/
|
||||
ipcMain.handle('abortDownload', async (_event, fileName) => {
|
||||
ipcMain.handle(DownloadRoute.abortDownload, async (_event, fileName) => {
|
||||
const rq = DownloadManager.instance.networkRequests[fileName]
|
||||
DownloadManager.instance.networkRequests[fileName] = undefined
|
||||
rq?.abort()
|
||||
})
|
||||
|
||||
ipcMain.handle('getResourcePath', async (_event) => {
|
||||
return getResourcePath()
|
||||
})
|
||||
|
||||
/**
|
||||
* Downloads a file from a given URL.
|
||||
* @param _event - The IPC event object.
|
||||
* @param url - The URL to download the file from.
|
||||
* @param fileName - The name to give the downloaded file.
|
||||
*/
|
||||
ipcMain.handle('downloadFile', async (_event, url, fileName) => {
|
||||
ipcMain.handle(DownloadRoute.downloadFile, async (_event, url, fileName) => {
|
||||
const userDataPath = join(app.getPath('home'), 'jan')
|
||||
const destination = resolve(userDataPath, fileName)
|
||||
const rq = request(url)
|
||||
@ -56,7 +52,7 @@ export function handleDownloaderIPCs() {
|
||||
progress(rq, {})
|
||||
.on('progress', function (state: any) {
|
||||
WindowManager?.instance.currentWindow?.webContents.send(
|
||||
'FILE_DOWNLOAD_UPDATE',
|
||||
DownloadEvent.onFileDownloadUpdate,
|
||||
{
|
||||
...state,
|
||||
fileName,
|
||||
@ -65,7 +61,7 @@ export function handleDownloaderIPCs() {
|
||||
})
|
||||
.on('error', function (err: Error) {
|
||||
WindowManager?.instance.currentWindow?.webContents.send(
|
||||
'FILE_DOWNLOAD_ERROR',
|
||||
DownloadEvent.onFileDownloadError,
|
||||
{
|
||||
fileName,
|
||||
err,
|
||||
@ -75,7 +71,7 @@ export function handleDownloaderIPCs() {
|
||||
.on('end', function () {
|
||||
if (DownloadManager.instance.networkRequests[fileName]) {
|
||||
WindowManager?.instance.currentWindow?.webContents.send(
|
||||
'FILE_DOWNLOAD_COMPLETE',
|
||||
DownloadEvent.onFileDownloadSuccess,
|
||||
{
|
||||
fileName,
|
||||
}
|
||||
@ -83,7 +79,7 @@ export function handleDownloaderIPCs() {
|
||||
DownloadManager.instance.setRequest(fileName, undefined)
|
||||
} else {
|
||||
WindowManager?.instance.currentWindow?.webContents.send(
|
||||
'FILE_DOWNLOAD_ERROR',
|
||||
DownloadEvent.onFileDownloadError,
|
||||
{
|
||||
fileName,
|
||||
err: 'Download cancelled',
|
||||
|
||||
@ -11,6 +11,7 @@ import { getExtension } from './../extension/store'
|
||||
import { removeExtension } from './../extension/store'
|
||||
import Extension from './../extension/extension'
|
||||
import { getResourcePath, userSpacePath } from './../utils/path'
|
||||
import { ExtensionRoute } from '@janhq/core'
|
||||
|
||||
export function handleExtensionIPCs() {
|
||||
/**MARK: General handlers */
|
||||
@ -23,7 +24,7 @@ export function handleExtensionIPCs() {
|
||||
* @returns The result of the invoked function.
|
||||
*/
|
||||
ipcMain.handle(
|
||||
'extension:invokeExtensionFunc',
|
||||
ExtensionRoute.invokeExtensionFunc,
|
||||
async (_event, modulePath, method, ...args) => {
|
||||
const module = require(
|
||||
/* webpackIgnore: true */ join(userSpacePath, 'extensions', modulePath)
|
||||
@ -44,81 +45,59 @@ export function handleExtensionIPCs() {
|
||||
* @param _event - The IPC event object.
|
||||
* @returns An array of paths to the base extensions.
|
||||
*/
|
||||
ipcMain.handle('extension:baseExtensions', async (_event) => {
|
||||
ipcMain.handle(ExtensionRoute.baseExtensions, async (_event) => {
|
||||
const baseExtensionPath = join(getResourcePath(), 'pre-install')
|
||||
return readdirSync(baseExtensionPath)
|
||||
.filter((file) => extname(file) === '.tgz')
|
||||
.map((file) => join(baseExtensionPath, file))
|
||||
})
|
||||
|
||||
/**
|
||||
* Returns the path to the user's extension directory.
|
||||
* @param _event - The IPC event extension.
|
||||
* @returns The path to the user's extension directory.
|
||||
*/
|
||||
ipcMain.handle('extension:extensionPath', async (_event) => {
|
||||
return join(userSpacePath, 'extensions')
|
||||
})
|
||||
|
||||
/**MARK: Extension Manager handlers */
|
||||
ipcMain.handle('extension:install', async (e, extensions) => {
|
||||
ipcMain.handle(ExtensionRoute.installExtension, async (e, extensions) => {
|
||||
// Install and activate all provided extensions
|
||||
const installed = await installExtensions(extensions)
|
||||
return JSON.parse(JSON.stringify(installed))
|
||||
})
|
||||
|
||||
// Register IPC route to uninstall a extension
|
||||
ipcMain.handle('extension:uninstall', async (e, extensions, reload) => {
|
||||
// Uninstall all provided extensions
|
||||
for (const ext of extensions) {
|
||||
const extension = getExtension(ext)
|
||||
await extension.uninstall()
|
||||
if (extension.name) removeExtension(extension.name)
|
||||
}
|
||||
ipcMain.handle(
|
||||
ExtensionRoute.uninstallExtension,
|
||||
async (e, extensions, reload) => {
|
||||
// Uninstall all provided extensions
|
||||
for (const ext of extensions) {
|
||||
const extension = getExtension(ext)
|
||||
await extension.uninstall()
|
||||
if (extension.name) removeExtension(extension.name)
|
||||
}
|
||||
|
||||
// Reload all renderer pages if needed
|
||||
reload && webContents.getAllWebContents().forEach((wc) => wc.reload())
|
||||
return true
|
||||
})
|
||||
// Reload all renderer pages if needed
|
||||
reload && webContents.getAllWebContents().forEach((wc) => wc.reload())
|
||||
return true
|
||||
}
|
||||
)
|
||||
|
||||
// Register IPC route to update a extension
|
||||
ipcMain.handle('extension:update', async (e, extensions, reload) => {
|
||||
// Update all provided extensions
|
||||
const updated: Extension[] = []
|
||||
for (const ext of extensions) {
|
||||
const extension = getExtension(ext)
|
||||
const res = await extension.update()
|
||||
if (res) updated.push(extension)
|
||||
ipcMain.handle(
|
||||
ExtensionRoute.updateExtension,
|
||||
async (e, extensions, reload) => {
|
||||
// Update all provided extensions
|
||||
const updated: Extension[] = []
|
||||
for (const ext of extensions) {
|
||||
const extension = getExtension(ext)
|
||||
const res = await extension.update()
|
||||
if (res) updated.push(extension)
|
||||
}
|
||||
|
||||
// Reload all renderer pages if needed
|
||||
if (updated.length && reload)
|
||||
webContents.getAllWebContents().forEach((wc) => wc.reload())
|
||||
|
||||
return JSON.parse(JSON.stringify(updated))
|
||||
}
|
||||
|
||||
// Reload all renderer pages if needed
|
||||
if (updated.length && reload)
|
||||
webContents.getAllWebContents().forEach((wc) => wc.reload())
|
||||
|
||||
return JSON.parse(JSON.stringify(updated))
|
||||
})
|
||||
|
||||
// Register IPC route to check if updates are available for a extension
|
||||
ipcMain.handle('extension:updatesAvailable', (e, names) => {
|
||||
const extensions = names
|
||||
? names.map((name: string) => getExtension(name))
|
||||
: getAllExtensions()
|
||||
|
||||
const updates: Record<string, Extension> = {}
|
||||
for (const extension of extensions) {
|
||||
updates[extension.name] = extension.isUpdateAvailable()
|
||||
}
|
||||
return updates
|
||||
})
|
||||
)
|
||||
|
||||
// Register IPC route to get the list of active extensions
|
||||
ipcMain.handle('extension:getActiveExtensions', () => {
|
||||
ipcMain.handle(ExtensionRoute.getActiveExtensions, () => {
|
||||
return JSON.parse(JSON.stringify(getActiveExtensions()))
|
||||
})
|
||||
|
||||
// Register IPC route to toggle the active state of a extension
|
||||
ipcMain.handle('extension:toggleExtensionActive', (e, plg, active) => {
|
||||
const extension = getExtension(plg)
|
||||
return JSON.parse(JSON.stringify(extension.setActive(active)))
|
||||
})
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import fse from 'fs-extra'
|
||||
import { join } from 'path'
|
||||
import readline from 'readline'
|
||||
import { userSpacePath } from './../utils/path'
|
||||
import { FileSystemRoute } from '@janhq/core'
|
||||
|
||||
/**
|
||||
* Handles file system operations.
|
||||
@ -15,7 +16,7 @@ export function handleFsIPCs() {
|
||||
* @returns A promise that resolves with the path to the user data directory.
|
||||
*/
|
||||
ipcMain.handle(
|
||||
'getUserSpace',
|
||||
FileSystemRoute.getUserSpace,
|
||||
(): Promise<string> => Promise.resolve(userSpacePath)
|
||||
)
|
||||
|
||||
@ -25,12 +26,15 @@ export function handleFsIPCs() {
|
||||
* @param path - The path to check.
|
||||
* @returns A promise that resolves with a boolean indicating whether the path is a directory.
|
||||
*/
|
||||
ipcMain.handle('isDirectory', (_event, path: string): Promise<boolean> => {
|
||||
const fullPath = join(userSpacePath, path)
|
||||
return Promise.resolve(
|
||||
fs.existsSync(fullPath) && fs.lstatSync(fullPath).isDirectory()
|
||||
)
|
||||
})
|
||||
ipcMain.handle(
|
||||
FileSystemRoute.isDirectory,
|
||||
(_event, path: string): Promise<boolean> => {
|
||||
const fullPath = join(userSpacePath, path)
|
||||
return Promise.resolve(
|
||||
fs.existsSync(fullPath) && fs.lstatSync(fullPath).isDirectory()
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Reads a file from the user data directory.
|
||||
@ -38,17 +42,20 @@ export function handleFsIPCs() {
|
||||
* @param path - The path of the file to read.
|
||||
* @returns A promise that resolves with the contents of the file.
|
||||
*/
|
||||
ipcMain.handle('readFile', async (event, path: string): Promise<string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.readFile(join(userSpacePath, path), 'utf8', (err, data) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
} else {
|
||||
resolve(data)
|
||||
}
|
||||
ipcMain.handle(
|
||||
FileSystemRoute.readFile,
|
||||
async (event, path: string): Promise<string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.readFile(join(userSpacePath, path), 'utf8', (err, data) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
} else {
|
||||
resolve(data)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Checks whether a file exists in the user data directory.
|
||||
@ -56,7 +63,7 @@ export function handleFsIPCs() {
|
||||
* @param path - The path of the file to check.
|
||||
* @returns A promise that resolves with a boolean indicating whether the file exists.
|
||||
*/
|
||||
ipcMain.handle('exists', async (_event, path: string) => {
|
||||
ipcMain.handle(FileSystemRoute.exists, async (_event, path: string) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fullPath = join(userSpacePath, path)
|
||||
fs.existsSync(fullPath) ? resolve(true) : resolve(false)
|
||||
@ -71,7 +78,7 @@ export function handleFsIPCs() {
|
||||
* @returns A promise that resolves when the file has been written.
|
||||
*/
|
||||
ipcMain.handle(
|
||||
'writeFile',
|
||||
FileSystemRoute.writeFile,
|
||||
async (event, path: string, data: string): Promise<void> => {
|
||||
try {
|
||||
await fs.writeFileSync(join(userSpacePath, path), data, 'utf8')
|
||||
@ -87,13 +94,16 @@ export function handleFsIPCs() {
|
||||
* @param path - The path of the directory to create.
|
||||
* @returns A promise that resolves when the directory has been created.
|
||||
*/
|
||||
ipcMain.handle('mkdir', async (event, path: string): Promise<void> => {
|
||||
try {
|
||||
fs.mkdirSync(join(userSpacePath, path), { recursive: true })
|
||||
} catch (err) {
|
||||
console.error(`mkdir ${path} result: ${err}`)
|
||||
ipcMain.handle(
|
||||
FileSystemRoute.mkdir,
|
||||
async (event, path: string): Promise<void> => {
|
||||
try {
|
||||
fs.mkdirSync(join(userSpacePath, path), { recursive: true })
|
||||
} catch (err) {
|
||||
console.error(`mkdir ${path} result: ${err}`)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
/**
|
||||
* Removes a directory in the user data directory.
|
||||
@ -101,13 +111,16 @@ export function handleFsIPCs() {
|
||||
* @param path - The path of the directory to remove.
|
||||
* @returns A promise that resolves when the directory is removed successfully.
|
||||
*/
|
||||
ipcMain.handle('rmdir', async (event, path: string): Promise<void> => {
|
||||
try {
|
||||
await fs.rmSync(join(userSpacePath, path), { recursive: true })
|
||||
} catch (err) {
|
||||
console.error(`rmdir ${path} result: ${err}`)
|
||||
ipcMain.handle(
|
||||
FileSystemRoute.rmdir,
|
||||
async (event, path: string): Promise<void> => {
|
||||
try {
|
||||
await fs.rmSync(join(userSpacePath, path), { recursive: true })
|
||||
} catch (err) {
|
||||
console.error(`rmdir ${path} result: ${err}`)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
/**
|
||||
* Lists the files in a directory in the user data directory.
|
||||
@ -116,7 +129,7 @@ export function handleFsIPCs() {
|
||||
* @returns A promise that resolves with an array of file names.
|
||||
*/
|
||||
ipcMain.handle(
|
||||
'listFiles',
|
||||
FileSystemRoute.listFiles,
|
||||
async (event, path: string): Promise<string[]> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.readdir(join(userSpacePath, path), (err, files) => {
|
||||
@ -136,7 +149,7 @@ export function handleFsIPCs() {
|
||||
* @param filePath - The path to the file to delete.
|
||||
* @returns A string indicating the result of the operation.
|
||||
*/
|
||||
ipcMain.handle('deleteFile', async (_event, filePath) => {
|
||||
ipcMain.handle(FileSystemRoute.deleteFile, async (_event, filePath) => {
|
||||
try {
|
||||
await fs.unlinkSync(join(userSpacePath, filePath))
|
||||
} catch (err) {
|
||||
@ -151,19 +164,25 @@ export function handleFsIPCs() {
|
||||
* @param data - The data to append to the file.
|
||||
* @returns A promise that resolves when the file has been written.
|
||||
*/
|
||||
ipcMain.handle('appendFile', async (_event, path: string, data: string) => {
|
||||
try {
|
||||
await fs.appendFileSync(join(userSpacePath, path), data, 'utf8')
|
||||
} catch (err) {
|
||||
console.error(`appendFile ${path} result: ${err}`)
|
||||
ipcMain.handle(
|
||||
FileSystemRoute.appendFile,
|
||||
async (_event, path: string, data: string) => {
|
||||
try {
|
||||
await fs.appendFileSync(join(userSpacePath, path), data, 'utf8')
|
||||
} catch (err) {
|
||||
console.error(`appendFile ${path} result: ${err}`)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
ipcMain.handle('copyFile', async (_event, src: string, dest: string) => {
|
||||
console.debug(`Copying file from ${src} to ${dest}`)
|
||||
ipcMain.handle(
|
||||
FileSystemRoute.copyFile,
|
||||
async (_event, src: string, dest: string) => {
|
||||
console.debug(`Copying file from ${src} to ${dest}`)
|
||||
|
||||
return fse.copySync(src, dest, { overwrite: false })
|
||||
})
|
||||
return fse.copySync(src, dest, { overwrite: false })
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Reads a file line by line.
|
||||
@ -171,25 +190,28 @@ export function handleFsIPCs() {
|
||||
* @param path - The path of the file to read.
|
||||
* @returns A promise that resolves with the contents of the file.
|
||||
*/
|
||||
ipcMain.handle('readLineByLine', async (_event, path: string) => {
|
||||
const fullPath = join(userSpacePath, path)
|
||||
ipcMain.handle(
|
||||
FileSystemRoute.readLineByLine,
|
||||
async (_event, path: string) => {
|
||||
const fullPath = join(userSpacePath, path)
|
||||
|
||||
return new Promise((res, rej) => {
|
||||
try {
|
||||
const readInterface = readline.createInterface({
|
||||
input: fs.createReadStream(fullPath),
|
||||
})
|
||||
const lines: any = []
|
||||
readInterface
|
||||
.on('line', function (line) {
|
||||
lines.push(line)
|
||||
return new Promise((res, rej) => {
|
||||
try {
|
||||
const readInterface = readline.createInterface({
|
||||
input: fs.createReadStream(fullPath),
|
||||
})
|
||||
.on('close', function () {
|
||||
res(lines)
|
||||
})
|
||||
} catch (err) {
|
||||
rej(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
const lines: any = []
|
||||
readInterface
|
||||
.on('line', function (line) {
|
||||
lines.push(line)
|
||||
})
|
||||
.on('close', function () {
|
||||
res(lines)
|
||||
})
|
||||
} catch (err) {
|
||||
rej(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
import { ipcMain, nativeTheme } from "electron";
|
||||
|
||||
export function handleThemesIPCs() {
|
||||
/**
|
||||
* Handles the "setNativeThemeLight" IPC message by setting the native theme source to "light".
|
||||
* This will change the appearance of the app to the light theme.
|
||||
*/
|
||||
ipcMain.handle("setNativeThemeLight", () => {
|
||||
nativeTheme.themeSource = "light";
|
||||
});
|
||||
|
||||
/**
|
||||
* Handles the "setNativeThemeDark" IPC message by setting the native theme source to "dark".
|
||||
* This will change the appearance of the app to the dark theme.
|
||||
*/
|
||||
ipcMain.handle("setNativeThemeDark", () => {
|
||||
nativeTheme.themeSource = "dark";
|
||||
});
|
||||
|
||||
/**
|
||||
* Handles the "setNativeThemeSystem" IPC message by setting the native theme source to "system".
|
||||
* This will change the appearance of the app to match the system's current theme.
|
||||
*/
|
||||
ipcMain.handle("setNativeThemeSystem", () => {
|
||||
nativeTheme.themeSource = "system";
|
||||
});
|
||||
}
|
||||
@ -1,57 +1,58 @@
|
||||
import { app, dialog } from "electron";
|
||||
import { WindowManager } from "./../managers/window";
|
||||
import { autoUpdater } from "electron-updater";
|
||||
import { app, dialog } from 'electron'
|
||||
import { WindowManager } from './../managers/window'
|
||||
import { autoUpdater } from 'electron-updater'
|
||||
import { AppEvent } from '@janhq/core'
|
||||
|
||||
export function handleAppUpdates() {
|
||||
/* Should not check for update during development */
|
||||
if (!app.isPackaged) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
/* New Update Available */
|
||||
autoUpdater.on("update-available", async (_info: any) => {
|
||||
autoUpdater.on('update-available', async (_info: any) => {
|
||||
const action = await dialog.showMessageBox({
|
||||
message: `Update available. Do you want to download the latest update?`,
|
||||
buttons: ["Download", "Later"],
|
||||
});
|
||||
if (action.response === 0) await autoUpdater.downloadUpdate();
|
||||
});
|
||||
buttons: ['Download', 'Later'],
|
||||
})
|
||||
if (action.response === 0) await autoUpdater.downloadUpdate()
|
||||
})
|
||||
|
||||
/* App Update Completion Message */
|
||||
autoUpdater.on("update-downloaded", async (_info: any) => {
|
||||
autoUpdater.on('update-downloaded', async (_info: any) => {
|
||||
WindowManager.instance.currentWindow?.webContents.send(
|
||||
"APP_UPDATE_COMPLETE",
|
||||
AppEvent.onAppUpdateDownloadSuccess,
|
||||
{}
|
||||
);
|
||||
)
|
||||
const action = await dialog.showMessageBox({
|
||||
message: `Update downloaded. Please restart the application to apply the updates.`,
|
||||
buttons: ["Restart", "Later"],
|
||||
});
|
||||
buttons: ['Restart', 'Later'],
|
||||
})
|
||||
if (action.response === 0) {
|
||||
autoUpdater.quitAndInstall();
|
||||
autoUpdater.quitAndInstall()
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
/* App Update Error */
|
||||
autoUpdater.on("error", (info: any) => {
|
||||
autoUpdater.on('error', (info: any) => {
|
||||
WindowManager.instance.currentWindow?.webContents.send(
|
||||
"APP_UPDATE_ERROR",
|
||||
AppEvent.onAppUpdateDownloadError,
|
||||
{}
|
||||
);
|
||||
});
|
||||
)
|
||||
})
|
||||
|
||||
/* App Update Progress */
|
||||
autoUpdater.on("download-progress", (progress: any) => {
|
||||
console.debug("app update progress: ", progress.percent);
|
||||
autoUpdater.on('download-progress', (progress: any) => {
|
||||
console.debug('app update progress: ', progress.percent)
|
||||
WindowManager.instance.currentWindow?.webContents.send(
|
||||
"APP_UPDATE_PROGRESS",
|
||||
AppEvent.onAppUpdateDownloadUpdate,
|
||||
{
|
||||
percent: progress.percent,
|
||||
}
|
||||
);
|
||||
});
|
||||
autoUpdater.autoDownload = false;
|
||||
autoUpdater.autoInstallOnAppQuit = true;
|
||||
if (process.env.CI !== "e2e") {
|
||||
autoUpdater.checkForUpdates();
|
||||
)
|
||||
})
|
||||
autoUpdater.autoDownload = false
|
||||
autoUpdater.autoInstallOnAppQuit = true
|
||||
if (process.env.CI !== 'e2e') {
|
||||
autoUpdater.checkForUpdates()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,62 +0,0 @@
|
||||
import { shell } from 'electron'
|
||||
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
export function appInvokers() {
|
||||
const interfaces = {
|
||||
/**
|
||||
* Sets the native theme to light.
|
||||
*/
|
||||
setNativeThemeLight: () => ipcRenderer.invoke('setNativeThemeLight'),
|
||||
|
||||
/**
|
||||
* Sets the native theme to dark.
|
||||
*/
|
||||
setNativeThemeDark: () => ipcRenderer.invoke('setNativeThemeDark'),
|
||||
|
||||
/**
|
||||
* Sets the native theme to system default.
|
||||
*/
|
||||
setNativeThemeSystem: () => ipcRenderer.invoke('setNativeThemeSystem'),
|
||||
|
||||
/**
|
||||
* Retrieves the application data path.
|
||||
* @returns {Promise<string>} A promise that resolves to the application data path.
|
||||
*/
|
||||
appDataPath: () => ipcRenderer.invoke('appDataPath'),
|
||||
|
||||
/**
|
||||
* Retrieves the application version.
|
||||
* @returns {Promise<string>} A promise that resolves to the application version.
|
||||
*/
|
||||
appVersion: () => ipcRenderer.invoke('appVersion'),
|
||||
|
||||
/**
|
||||
* Opens an external URL.
|
||||
* @param {string} url - The URL to open.
|
||||
* @returns {Promise<void>} A promise that resolves when the URL has been opened.
|
||||
*/
|
||||
openExternalUrl: (url: string) =>
|
||||
ipcRenderer.invoke('openExternalUrl', url),
|
||||
|
||||
/**
|
||||
* Relaunches the application.
|
||||
* @returns {Promise<void>} A promise that resolves when the application has been relaunched.
|
||||
*/
|
||||
relaunch: () => ipcRenderer.invoke('relaunch'),
|
||||
|
||||
/**
|
||||
* Opens the application directory.
|
||||
* @returns {Promise<void>} A promise that resolves when the application directory has been opened.
|
||||
*/
|
||||
openAppDirectory: () => ipcRenderer.invoke('openAppDirectory'),
|
||||
|
||||
/**
|
||||
* Opens the file explorer at a specific path.
|
||||
* @param {string} path - The path to open in the file explorer.
|
||||
*/
|
||||
openFileExplorer: (path: string) => shell.openPath(path),
|
||||
}
|
||||
|
||||
return interfaces
|
||||
}
|
||||
@ -1,77 +0,0 @@
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
export function downloadInvokers() {
|
||||
const interfaces = {
|
||||
/**
|
||||
* Opens the file explorer at a specific path.
|
||||
* @param {string} path - The path to open in the file explorer.
|
||||
*/
|
||||
downloadFile: (url: string, path: string) =>
|
||||
ipcRenderer.invoke('downloadFile', url, path),
|
||||
|
||||
/**
|
||||
* Pauses the download of a file.
|
||||
* @param {string} fileName - The name of the file whose download should be paused.
|
||||
*/
|
||||
pauseDownload: (fileName: string) =>
|
||||
ipcRenderer.invoke('pauseDownload', fileName),
|
||||
|
||||
/**
|
||||
* Pauses the download of a file.
|
||||
* @param {string} fileName - The name of the file whose download should be paused.
|
||||
*/
|
||||
resumeDownload: (fileName: string) =>
|
||||
ipcRenderer.invoke('resumeDownload', fileName),
|
||||
|
||||
/**
|
||||
* Pauses the download of a file.
|
||||
* @param {string} fileName - The name of the file whose download should be paused.
|
||||
*/
|
||||
abortDownload: (fileName: string) =>
|
||||
ipcRenderer.invoke('abortDownload', fileName),
|
||||
|
||||
/**
|
||||
* Pauses the download of a file.
|
||||
* @param {string} fileName - The name of the file whose download should be paused.
|
||||
*/
|
||||
onFileDownloadUpdate: (callback: any) =>
|
||||
ipcRenderer.on('FILE_DOWNLOAD_UPDATE', callback),
|
||||
|
||||
/**
|
||||
* Listens for errors on file downloads.
|
||||
* @param {Function} callback - The function to call when there is an error.
|
||||
*/
|
||||
onFileDownloadError: (callback: any) =>
|
||||
ipcRenderer.on('FILE_DOWNLOAD_ERROR', callback),
|
||||
|
||||
/**
|
||||
* Listens for the successful completion of file downloads.
|
||||
* @param {Function} callback - The function to call when a download is complete.
|
||||
*/
|
||||
onFileDownloadSuccess: (callback: any) =>
|
||||
ipcRenderer.on('FILE_DOWNLOAD_COMPLETE', callback),
|
||||
|
||||
/**
|
||||
* Listens for updates on app update downloads.
|
||||
* @param {Function} callback - The function to call when there is an update.
|
||||
*/
|
||||
onAppUpdateDownloadUpdate: (callback: any) =>
|
||||
ipcRenderer.on('APP_UPDATE_PROGRESS', callback),
|
||||
|
||||
/**
|
||||
* Listens for errors on app update downloads.
|
||||
* @param {Function} callback - The function to call when there is an error.
|
||||
*/
|
||||
onAppUpdateDownloadError: (callback: any) =>
|
||||
ipcRenderer.on('APP_UPDATE_ERROR', callback),
|
||||
|
||||
/**
|
||||
* Listens for the successful completion of app update downloads.
|
||||
* @param {Function} callback - The function to call when an update download is complete.
|
||||
*/
|
||||
onAppUpdateDownloadSuccess: (callback: any) =>
|
||||
ipcRenderer.on('APP_UPDATE_COMPLETE', callback),
|
||||
}
|
||||
|
||||
return interfaces
|
||||
}
|
||||
@ -1,78 +0,0 @@
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
export function extensionInvokers() {
|
||||
const interfaces = {
|
||||
/**
|
||||
* Installs the given extensions.
|
||||
* @param {any[]} extensions - The extensions to install.
|
||||
*/
|
||||
install(extensions: any[]) {
|
||||
return ipcRenderer.invoke('extension:install', extensions)
|
||||
},
|
||||
/**
|
||||
* Uninstalls the given extensions.
|
||||
* @param {any[]} extensions - The extensions to uninstall.
|
||||
* @param {boolean} reload - Whether to reload after uninstalling.
|
||||
*/
|
||||
uninstall(extensions: any[], reload: boolean) {
|
||||
return ipcRenderer.invoke('extension:uninstall', extensions, reload)
|
||||
},
|
||||
/**
|
||||
* Retrieves the active extensions.
|
||||
*/
|
||||
getActive() {
|
||||
return ipcRenderer.invoke('extension:getActiveExtensions')
|
||||
},
|
||||
/**
|
||||
* Updates the given extensions.
|
||||
* @param {any[]} extensions - The extensions to update.
|
||||
* @param {boolean} reload - Whether to reload after updating.
|
||||
*/
|
||||
update(extensions: any[], reload: boolean) {
|
||||
return ipcRenderer.invoke('extension:update', extensions, reload)
|
||||
},
|
||||
/**
|
||||
* Checks if updates are available for the given extension.
|
||||
* @param {any} extension - The extension to check for updates.
|
||||
*/
|
||||
updatesAvailable(extension: any) {
|
||||
return ipcRenderer.invoke('extension:updatesAvailable', extension)
|
||||
},
|
||||
/**
|
||||
* Toggles the active state of the given extension.
|
||||
* @param {any} extension - The extension to toggle.
|
||||
* @param {boolean} active - The new active state.
|
||||
*/
|
||||
toggleActive(extension: any, active: boolean) {
|
||||
return ipcRenderer.invoke(
|
||||
'extension:toggleExtensionActive',
|
||||
extension,
|
||||
active
|
||||
)
|
||||
},
|
||||
|
||||
/**
|
||||
* Invokes a function of the given extension.
|
||||
* @param {any} extension - The extension whose function should be invoked.
|
||||
* @param {any} method - The function to invoke.
|
||||
* @param {any[]} args - The arguments to pass to the function.
|
||||
*/
|
||||
invokeExtensionFunc: (extension: any, method: any, ...args: any[]) =>
|
||||
ipcRenderer.invoke(
|
||||
'extension:invokeExtensionFunc',
|
||||
extension,
|
||||
method,
|
||||
...args
|
||||
),
|
||||
/**
|
||||
* Retrieves the base extensions.
|
||||
*/
|
||||
baseExtensions: () => ipcRenderer.invoke('extension:baseExtensions'),
|
||||
/**
|
||||
* Retrieves the extension path.
|
||||
*/
|
||||
extensionPath: () => ipcRenderer.invoke('extension:extensionPath'),
|
||||
}
|
||||
|
||||
return interfaces
|
||||
}
|
||||
@ -1,93 +0,0 @@
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
export function fsInvokers() {
|
||||
const interfaces = {
|
||||
/**
|
||||
* Deletes a file at the specified path.
|
||||
* @param {string} filePath - The path of the file to delete.
|
||||
*/
|
||||
deleteFile: (filePath: string) =>
|
||||
ipcRenderer.invoke('deleteFile', filePath),
|
||||
|
||||
/**
|
||||
* Checks if the path points to a directory.
|
||||
* @param {string} filePath - The path to check.
|
||||
*/
|
||||
isDirectory: (filePath: string) =>
|
||||
ipcRenderer.invoke('isDirectory', filePath),
|
||||
|
||||
/**
|
||||
* Retrieves the user's space.
|
||||
*/
|
||||
getUserSpace: () => ipcRenderer.invoke('getUserSpace'),
|
||||
|
||||
/**
|
||||
* Reads a file at the specified path.
|
||||
* @param {string} path - The path of the file to read.
|
||||
*/
|
||||
readFile: (path: string) => ipcRenderer.invoke('readFile', path),
|
||||
|
||||
/**
|
||||
* Reads a file at the specified path.
|
||||
* @param {string} path - The path of the file to read.
|
||||
*/
|
||||
exists: (path: string) => ipcRenderer.invoke('exists', path),
|
||||
|
||||
/**
|
||||
* Writes data to a file at the specified path.
|
||||
* @param {string} path - The path of the file to write to.
|
||||
* @param {string} data - The data to write.
|
||||
*/
|
||||
writeFile: (path: string, data: string) =>
|
||||
ipcRenderer.invoke('writeFile', path, data),
|
||||
|
||||
/**
|
||||
* Lists the files in a directory at the specified path.
|
||||
* @param {string} path - The path of the directory to list files from.
|
||||
*/
|
||||
listFiles: (path: string) => ipcRenderer.invoke('listFiles', path),
|
||||
|
||||
/**
|
||||
* Appends data to a file at the specified path.
|
||||
* @param {string} path - The path of the file to append to.
|
||||
* @param {string} data - The data to append.
|
||||
*/
|
||||
appendFile: (path: string, data: string) =>
|
||||
ipcRenderer.invoke('appendFile', path, data),
|
||||
|
||||
/**
|
||||
* Reads a file line by line at the specified path.
|
||||
* @param {string} path - The path of the file to read.
|
||||
*/
|
||||
readLineByLine: (path: string) =>
|
||||
ipcRenderer.invoke('readLineByLine', path),
|
||||
|
||||
/**
|
||||
* Creates a directory at the specified path.
|
||||
* @param {string} path - The path where the directory should be created.
|
||||
*/
|
||||
mkdir: (path: string) => ipcRenderer.invoke('mkdir', path),
|
||||
|
||||
/**
|
||||
* Removes a directory at the specified path.
|
||||
* @param {string} path - The path of the directory to remove.
|
||||
*/
|
||||
rmdir: (path: string) => ipcRenderer.invoke('rmdir', path),
|
||||
|
||||
/**
|
||||
* Copies a file from the source path to the destination path.
|
||||
* @param {string} src - The source path of the file to copy.
|
||||
* @param {string} dest - The destination path where the file should be copied.
|
||||
*/
|
||||
copyFile: (src: string, dest: string) => ipcRenderer.invoke('copyFile', src, dest),
|
||||
|
||||
/**
|
||||
* Retrieves the resource path.
|
||||
* @returns {Promise<string>} A promise that resolves to the resource path.
|
||||
*/
|
||||
getResourcePath: () => ipcRenderer.invoke('getResourcePath'),
|
||||
|
||||
}
|
||||
|
||||
return interfaces
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
import { app, BrowserWindow } from 'electron'
|
||||
import { join } from 'path'
|
||||
import { setupMenu } from './utils/menu'
|
||||
import { createUserSpace, getResourcePath } from './utils/path'
|
||||
import { createUserSpace } from './utils/path'
|
||||
|
||||
/**
|
||||
* Managers
|
||||
@ -14,7 +14,6 @@ import { ExtensionManager } from './managers/extension'
|
||||
* IPC Handlers
|
||||
**/
|
||||
import { handleDownloaderIPCs } from './handlers/download'
|
||||
import { handleThemesIPCs } from './handlers/theme'
|
||||
import { handleExtensionIPCs } from './handlers/extension'
|
||||
import { handleAppIPCs } from './handlers/app'
|
||||
import { handleAppUpdates } from './handlers/update'
|
||||
@ -79,7 +78,6 @@ function createMainWindow() {
|
||||
function handleIPCs() {
|
||||
handleFsIPCs()
|
||||
handleDownloaderIPCs()
|
||||
handleThemesIPCs()
|
||||
handleExtensionIPCs()
|
||||
handleAppIPCs()
|
||||
}
|
||||
|
||||
@ -67,6 +67,7 @@
|
||||
"build:publish:linux": "tsc -p . && electron-builder -p onTagOrDraft -l deb"
|
||||
},
|
||||
"dependencies": {
|
||||
"@janhq/core": "link:./core",
|
||||
"@npmcli/arborist": "^7.1.0",
|
||||
"@types/request": "^2.48.12",
|
||||
"@uiball/loaders": "^1.3.0",
|
||||
|
||||
@ -3,19 +3,27 @@
|
||||
* @module preload
|
||||
*/
|
||||
|
||||
// TODO: Refactor this file for less dependencies and more modularity
|
||||
// TODO: Most of the APIs should be done using RestAPIs from extensions
|
||||
import { APIEvents, APIRoutes } from '@janhq/core'
|
||||
import { contextBridge, ipcRenderer } from 'electron'
|
||||
|
||||
import { fsInvokers } from './invokers/fs'
|
||||
import { appInvokers } from './invokers/app'
|
||||
import { downloadInvokers } from './invokers/download'
|
||||
import { extensionInvokers } from './invokers/extension'
|
||||
const interfaces: { [key: string]: (...args: any[]) => any } = {}
|
||||
|
||||
const { contextBridge } = require('electron')
|
||||
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
...extensionInvokers(),
|
||||
...downloadInvokers(),
|
||||
...fsInvokers(),
|
||||
...appInvokers(),
|
||||
// Loop over each route in APIRoutes
|
||||
APIRoutes.forEach((method) => {
|
||||
// For each method, create a function on the interfaces object
|
||||
// This function invokes the method on the ipcRenderer with any provided arguments
|
||||
interfaces[method] = (...args: any[]) => ipcRenderer.invoke(method, ...args)
|
||||
})
|
||||
|
||||
// Loop over each method in APIEvents
|
||||
APIEvents.forEach((method) => {
|
||||
// For each method, create a function on the interfaces object
|
||||
// This function sets up an event listener on the ipcRenderer for the method
|
||||
// The handler for the event is provided as an argument to the function
|
||||
interfaces[method] = (handler: any) => ipcRenderer.on(method, handler)
|
||||
})
|
||||
// Expose the 'interfaces' object in the main world under the name 'electronAPI'
|
||||
// This allows the renderer process to access these methods directly
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
...interfaces,
|
||||
})
|
||||
|
||||
@ -118,7 +118,7 @@ export default function EventHandler({ children }: { children: ReactNode }) {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (window.core.events) {
|
||||
if (window.core?.events) {
|
||||
events.on(EventName.OnMessageResponse, handleNewMessageResponse)
|
||||
events.on(EventName.OnMessageUpdate, handleMessageResponseUpdate)
|
||||
events.on(EventName.OnModelReady, handleModelReady)
|
||||
|
||||
@ -53,7 +53,7 @@ const Providers = (props: PropsWithChildren) => {
|
||||
useEffect(() => {
|
||||
if (setupCore) {
|
||||
// Electron
|
||||
if (window && window.core.api) {
|
||||
if (window && window.core?.api) {
|
||||
setupExtensions()
|
||||
} else {
|
||||
// Host
|
||||
|
||||
@ -58,7 +58,7 @@ export class ExtensionManager {
|
||||
* @returns An array of extensions.
|
||||
*/
|
||||
async getActive(): Promise<Extension[]> {
|
||||
const res = await window.core.api?.getActive()
|
||||
const res = await window.core?.api?.getActiveExtensions()
|
||||
if (!res || !Array.isArray(res)) return []
|
||||
|
||||
const extensions: Extension[] = res.map(
|
||||
@ -119,7 +119,7 @@ export class ExtensionManager {
|
||||
if (typeof window === 'undefined') {
|
||||
return
|
||||
}
|
||||
const res = await window.core.api?.install(extensions)
|
||||
const res = await window.core?.api?.installExtension(extensions)
|
||||
if (res.cancelled) return false
|
||||
return res.map(async (ext: any) => {
|
||||
const extension = new Extension(ext.name, ext.url, ext.active)
|
||||
@ -138,7 +138,7 @@ export class ExtensionManager {
|
||||
if (typeof window === 'undefined') {
|
||||
return
|
||||
}
|
||||
return window.core.api?.uninstall(extensions, reload)
|
||||
return window.core?.api?.uninstallExtension(extensions, reload)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,6 @@ import {
|
||||
threadsAtom,
|
||||
setActiveThreadIdAtom,
|
||||
threadStatesAtom,
|
||||
activeThreadAtom,
|
||||
updateThreadAtom,
|
||||
} from '@/helpers/atoms/Conversation.atom'
|
||||
|
||||
@ -67,7 +66,7 @@ export const useCreateNewThread = () => {
|
||||
top_p: 0,
|
||||
stream: false,
|
||||
},
|
||||
engine: undefined
|
||||
engine: undefined,
|
||||
},
|
||||
instructions: assistant.instructions,
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ export function useGetAppVersion() {
|
||||
}, [])
|
||||
|
||||
const getAppVersion = () => {
|
||||
window.core.api?.appVersion().then((version: string | undefined) => {
|
||||
window.core?.api?.appVersion().then((version: string | undefined) => {
|
||||
setVersion(version ?? '')
|
||||
})
|
||||
}
|
||||
|
||||
@ -67,7 +67,7 @@ const ExtensionCatalog = () => {
|
||||
// Send the filename of the to be installed extension
|
||||
// to the main process for installation
|
||||
const installed = await extensionManager.install([extensionFile])
|
||||
if (installed) window.core.api?.relaunch()
|
||||
if (installed) window.core?.api?.relaunch()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,7 +80,7 @@ const ExtensionCatalog = () => {
|
||||
// Send the filename of the to be uninstalled extension
|
||||
// to the main process for removal
|
||||
const res = await extensionManager.uninstall([name])
|
||||
if (res) window.core.api?.relaunch()
|
||||
if (res) window.core?.api?.relaunch()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
8
web/types/index.d.ts
vendored
8
web/types/index.d.ts
vendored
@ -1,11 +1,17 @@
|
||||
import { APIFunctions } from '@janhq/core'
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
export {}
|
||||
|
||||
declare global {
|
||||
declare const PLUGIN_CATALOG: string
|
||||
declare const VERSION: string
|
||||
interface Core {
|
||||
api: APIFunctions
|
||||
events: EventEmitter
|
||||
}
|
||||
interface Window {
|
||||
core?: any | undefined
|
||||
core?: Core | undefined
|
||||
electronAPI?: any | undefined
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user