// See the Electron documentation for details on how to use preload scripts: // https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts import { contextBridge, ipcRenderer } from "electron"; import type { GameShop, DownloadProgress, UserPreferences, AppUpdaterEvent, StartGameDownloadPayload, GameRunning, FriendRequestAction, UpdateProfileRequest, CatalogueSearchPayload, SeedingStatus, GameAchievement, } from "@types"; import type { AuthPage, CatalogueCategory } from "@shared"; import type { AxiosProgressEvent } from "axios"; contextBridge.exposeInMainWorld("electron", { /* Torrenting */ startGameDownload: (payload: StartGameDownloadPayload) => ipcRenderer.invoke("startGameDownload", payload), cancelGameDownload: (shop: GameShop, objectId: string) => ipcRenderer.invoke("cancelGameDownload", shop, objectId), pauseGameDownload: (shop: GameShop, objectId: string) => ipcRenderer.invoke("pauseGameDownload", shop, objectId), resumeGameDownload: (shop: GameShop, objectId: string) => ipcRenderer.invoke("resumeGameDownload", shop, objectId), pauseGameSeed: (shop: GameShop, objectId: string) => ipcRenderer.invoke("pauseGameSeed", shop, objectId), resumeGameSeed: (shop: GameShop, objectId: string) => ipcRenderer.invoke("resumeGameSeed", shop, objectId), onDownloadProgress: (cb: (value: DownloadProgress | null) => void) => { const listener = ( _event: Electron.IpcRendererEvent, value: DownloadProgress | null ) => cb(value); ipcRenderer.on("on-download-progress", listener); return () => ipcRenderer.removeListener("on-download-progress", listener); }, onHardDelete: (cb: () => void) => { const listener = (_event: Electron.IpcRendererEvent) => cb(); ipcRenderer.on("on-hard-delete", listener); return () => ipcRenderer.removeListener("on-hard-delete", listener); }, onSeedingStatus: (cb: (value: SeedingStatus[]) => void) => { const listener = ( _event: Electron.IpcRendererEvent, value: SeedingStatus[] ) => cb(value); ipcRenderer.on("on-seeding-status", listener); return () => ipcRenderer.removeListener("on-seeding-status", listener); }, /* Catalogue */ searchGames: (payload: CatalogueSearchPayload, take: number, skip: number) => ipcRenderer.invoke("searchGames", payload, take, skip), getCatalogue: (category: CatalogueCategory) => ipcRenderer.invoke("getCatalogue", category), getGameShopDetails: (objectId: string, shop: GameShop, language: string) => ipcRenderer.invoke("getGameShopDetails", objectId, shop, language), getRandomGame: () => ipcRenderer.invoke("getRandomGame"), getHowLongToBeat: (objectId: string, shop: GameShop) => ipcRenderer.invoke("getHowLongToBeat", objectId, shop), getGameStats: (objectId: string, shop: GameShop) => ipcRenderer.invoke("getGameStats", objectId, shop), getTrendingGames: () => ipcRenderer.invoke("getTrendingGames"), onUpdateAchievements: ( objectId: string, shop: GameShop, cb: (achievements: GameAchievement[]) => void ) => { const listener = ( _event: Electron.IpcRendererEvent, achievements: GameAchievement[] ) => cb(achievements); ipcRenderer.on(`on-update-achievements-${objectId}-${shop}`, listener); return () => ipcRenderer.removeListener( `on-update-achievements-${objectId}-${shop}`, listener ); }, /* User preferences */ getUserPreferences: () => ipcRenderer.invoke("getUserPreferences"), updateUserPreferences: (preferences: UserPreferences) => ipcRenderer.invoke("updateUserPreferences", preferences), autoLaunch: (autoLaunchProps: { enabled: boolean; minimized: boolean }) => ipcRenderer.invoke("autoLaunch", autoLaunchProps), authenticateRealDebrid: (apiToken: string) => ipcRenderer.invoke("authenticateRealDebrid", apiToken), authenticateTorBox: (apiToken: string) => ipcRenderer.invoke("authenticateTorBox", apiToken), /* Download sources */ putDownloadSource: (objectIds: string[]) => ipcRenderer.invoke("putDownloadSource", objectIds), /* Library */ addGameToLibrary: (shop: GameShop, objectId: string, title: string) => ipcRenderer.invoke("addGameToLibrary", shop, objectId, title), createGameShortcut: (shop: GameShop, objectId: string) => ipcRenderer.invoke("createGameShortcut", shop, objectId), updateExecutablePath: ( shop: GameShop, objectId: string, executablePath: string | null ) => ipcRenderer.invoke("updateExecutablePath", shop, objectId, executablePath), addGameToFavorites: (shop: GameShop, objectId: string) => ipcRenderer.invoke("addGameToFavorites", shop, objectId), removeGameFromFavorites: (shop: GameShop, objectId: string) => ipcRenderer.invoke("removeGameFromFavorites", shop, objectId), updateLaunchOptions: ( shop: GameShop, objectId: string, launchOptions: string | null ) => ipcRenderer.invoke("updateLaunchOptions", shop, objectId, launchOptions), selectGameWinePrefix: ( shop: GameShop, objectId: string, winePrefixPath: string | null ) => ipcRenderer.invoke("selectGameWinePrefix", shop, objectId, winePrefixPath), verifyExecutablePathInUse: (executablePath: string) => ipcRenderer.invoke("verifyExecutablePathInUse", executablePath), getLibrary: () => ipcRenderer.invoke("getLibrary"), openGameInstaller: (shop: GameShop, objectId: string) => ipcRenderer.invoke("openGameInstaller", shop, objectId), openGameInstallerPath: (shop: GameShop, objectId: string) => ipcRenderer.invoke("openGameInstallerPath", shop, objectId), openGameExecutablePath: (shop: GameShop, objectId: string) => ipcRenderer.invoke("openGameExecutablePath", shop, objectId), openGame: ( shop: GameShop, objectId: string, executablePath: string, launchOptions?: string | null ) => ipcRenderer.invoke( "openGame", shop, objectId, executablePath, launchOptions ), closeGame: (shop: GameShop, objectId: string) => ipcRenderer.invoke("closeGame", shop, objectId), removeGameFromLibrary: (shop: GameShop, objectId: string) => ipcRenderer.invoke("removeGameFromLibrary", shop, objectId), removeGame: (shop: GameShop, objectId: string) => ipcRenderer.invoke("removeGame", shop, objectId), deleteGameFolder: (shop: GameShop, objectId: string) => ipcRenderer.invoke("deleteGameFolder", shop, objectId), getGameByObjectId: (shop: GameShop, objectId: string) => ipcRenderer.invoke("getGameByObjectId", shop, objectId), resetGameAchievements: (shop: GameShop, objectId: string) => ipcRenderer.invoke("resetGameAchievements", shop, objectId), onGamesRunning: ( cb: ( gamesRunning: Pick[] ) => void ) => { const listener = (_event: Electron.IpcRendererEvent, gamesRunning) => cb(gamesRunning); ipcRenderer.on("on-games-running", listener); return () => ipcRenderer.removeListener("on-games-running", listener); }, onLibraryBatchComplete: (cb: () => void) => { const listener = (_event: Electron.IpcRendererEvent) => cb(); ipcRenderer.on("on-library-batch-complete", listener); return () => ipcRenderer.removeListener("on-library-batch-complete", listener); }, onAchievementUnlocked: (cb: () => void) => { const listener = (_event: Electron.IpcRendererEvent) => cb(); ipcRenderer.on("on-achievement-unlocked", listener); return () => ipcRenderer.removeListener("on-achievement-unlocked", listener); }, /* Hardware */ getDiskFreeSpace: (path: string) => ipcRenderer.invoke("getDiskFreeSpace", path), checkFolderWritePermission: (path: string) => ipcRenderer.invoke("checkFolderWritePermission", path), /* Cloud save */ uploadSaveGame: ( objectId: string, shop: GameShop, downloadOptionTitle: string | null ) => ipcRenderer.invoke("uploadSaveGame", objectId, shop, downloadOptionTitle), downloadGameArtifact: ( objectId: string, shop: GameShop, gameArtifactId: string ) => ipcRenderer.invoke("downloadGameArtifact", objectId, shop, gameArtifactId), getGameArtifacts: (objectId: string, shop: GameShop) => ipcRenderer.invoke("getGameArtifacts", objectId, shop), getGameBackupPreview: (objectId: string, shop: GameShop) => ipcRenderer.invoke("getGameBackupPreview", objectId, shop), deleteGameArtifact: (gameArtifactId: string) => ipcRenderer.invoke("deleteGameArtifact", gameArtifactId), selectGameBackupPath: ( shop: GameShop, objectId: string, backupPath: string | null ) => ipcRenderer.invoke("selectGameBackupPath", shop, objectId, backupPath), onUploadComplete: (objectId: string, shop: GameShop, cb: () => void) => { const listener = (_event: Electron.IpcRendererEvent) => cb(); ipcRenderer.on(`on-upload-complete-${objectId}-${shop}`, listener); return () => ipcRenderer.removeListener( `on-upload-complete-${objectId}-${shop}`, listener ); }, onBackupDownloadProgress: ( objectId: string, shop: GameShop, cb: (progress: AxiosProgressEvent) => void ) => { const listener = ( _event: Electron.IpcRendererEvent, progress: AxiosProgressEvent ) => cb(progress); ipcRenderer.on(`on-backup-download-progress-${objectId}-${shop}`, listener); return () => ipcRenderer.removeListener( `on-backup-download-progress-${objectId}-${shop}`, listener ); }, onBackupDownloadComplete: ( objectId: string, shop: GameShop, cb: () => void ) => { const listener = (_event: Electron.IpcRendererEvent) => cb(); ipcRenderer.on(`on-backup-download-complete-${objectId}-${shop}`, listener); return () => ipcRenderer.removeListener( `on-backup-download-complete-${objectId}-${shop}`, listener ); }, /* Misc */ ping: () => ipcRenderer.invoke("ping"), getVersion: () => ipcRenderer.invoke("getVersion"), getDefaultDownloadsPath: () => ipcRenderer.invoke("getDefaultDownloadsPath"), isStaging: () => ipcRenderer.invoke("isStaging"), isPortableVersion: () => ipcRenderer.invoke("isPortableVersion"), openExternal: (src: string) => ipcRenderer.invoke("openExternal", src), openCheckout: () => ipcRenderer.invoke("openCheckout"), showOpenDialog: (options: Electron.OpenDialogOptions) => ipcRenderer.invoke("showOpenDialog", options), showItemInFolder: (path: string) => ipcRenderer.invoke("showItemInFolder", path), getFeatures: () => ipcRenderer.invoke("getFeatures"), platform: process.platform, /* Auto update */ onAutoUpdaterEvent: (cb: (value: AppUpdaterEvent) => void) => { const listener = ( _event: Electron.IpcRendererEvent, value: AppUpdaterEvent ) => cb(value); ipcRenderer.on("autoUpdaterEvent", listener); return () => { ipcRenderer.removeListener("autoUpdaterEvent", listener); }; }, checkForUpdates: () => ipcRenderer.invoke("checkForUpdates"), restartAndInstallUpdate: () => ipcRenderer.invoke("restartAndInstallUpdate"), /* Profile */ getMe: () => ipcRenderer.invoke("getMe"), undoFriendship: (userId: string) => ipcRenderer.invoke("undoFriendship", userId), updateProfile: (updateProfile: UpdateProfileRequest) => ipcRenderer.invoke("updateProfile", updateProfile), processProfileImage: (imagePath: string) => ipcRenderer.invoke("processProfileImage", imagePath), getFriendRequests: () => ipcRenderer.invoke("getFriendRequests"), syncFriendRequests: () => ipcRenderer.invoke("syncFriendRequests"), updateFriendRequest: (userId: string, action: FriendRequestAction) => ipcRenderer.invoke("updateFriendRequest", userId, action), sendFriendRequest: (userId: string) => ipcRenderer.invoke("sendFriendRequest", userId), /* User */ getUser: (userId: string) => ipcRenderer.invoke("getUser", userId), blockUser: (userId: string) => ipcRenderer.invoke("blockUser", userId), unblockUser: (userId: string) => ipcRenderer.invoke("unblockUser", userId), getUserFriends: (userId: string, take: number, skip: number) => ipcRenderer.invoke("getUserFriends", userId, take, skip), getBlockedUsers: (take: number, skip: number) => ipcRenderer.invoke("getBlockedUsers", take, skip), getUserStats: (userId: string) => ipcRenderer.invoke("getUserStats", userId), reportUser: (userId: string, reason: string, description: string) => ipcRenderer.invoke("reportUser", userId, reason, description), getComparedUnlockedAchievements: ( objectId: string, shop: GameShop, userId: string ) => ipcRenderer.invoke( "getComparedUnlockedAchievements", objectId, shop, userId ), getUnlockedAchievements: (objectId: string, shop: GameShop) => ipcRenderer.invoke("getUnlockedAchievements", objectId, shop), /* Auth */ signOut: () => ipcRenderer.invoke("signOut"), openAuthWindow: (page: AuthPage) => ipcRenderer.invoke("openAuthWindow", page), getSessionHash: () => ipcRenderer.invoke("getSessionHash"), onSignIn: (cb: () => void) => { const listener = (_event: Electron.IpcRendererEvent) => cb(); ipcRenderer.on("on-signin", listener); return () => ipcRenderer.removeListener("on-signin", listener); }, onAccountUpdated: (cb: () => void) => { const listener = (_event: Electron.IpcRendererEvent) => cb(); ipcRenderer.on("on-account-updated", listener); return () => ipcRenderer.removeListener("on-account-updated", listener); }, onSignOut: (cb: () => void) => { const listener = (_event: Electron.IpcRendererEvent) => cb(); ipcRenderer.on("on-signout", listener); return () => ipcRenderer.removeListener("on-signout", listener); }, /* Notifications */ publishNewRepacksNotification: (newRepacksCount: number) => ipcRenderer.invoke("publishNewRepacksNotification", newRepacksCount), });