import { basename } from "node:path"; import open from "open"; import type { App as AppBase } from "../app.ts"; import { getLauncherInstalled } from "./launcherInstalled.ts"; import { type AppManifest, getManifestById, getManifestByPath, getManifests, } from "./manifest.ts"; const launcher = "epic"; /** An installed Epic Games Launcher app. */ export type App = AppBase & { launcher: typeof launcher; launchId: string; }; export const isFullyInstalled = ({ manifest: { bIsIncompleteInstall } }: App) => bIsIncompleteInstall !== true; /** Gets information about installed Epic Games Launcher apps. */ export async function* getApps() { const launcherInstalled = getLauncherInstalled(); for await (const _manifest of getManifests()) { const info = (await launcherInstalled) .find((x) => [x.artifactId, x.appName].includes(_manifest.appName)); if (info) { const manifest = { ...info, ..._manifest }; const { displayName: name, installLocation: path, namespaceId, catalogNamespace, itemId, catalogItemId, artifactId, appName, } = manifest; const id = typeof artifactId === "string" ? artifactId : appName; const launchId = [ typeof namespaceId === "string" ? namespaceId : catalogNamespace, typeof itemId === "string" ? itemId : catalogItemId, id, ].filter(Boolean).join(":"); yield { launcher, manifest, id, name, path, launchId, } satisfies App; } } } /** * Gets information about an installed Epic Games Launcher app. * * Resolves `undefined` if an app with a matching id cannot be found. * * @param id The ArtifactId or AppName of the app. */ export const getAppById = async (id: string) => { const [info, appManifest] = await Promise.all([ getLauncherInstalled() .then((apps) => apps.find((app) => [app.artifactId, app.appName].includes(id)) ), getManifestById(id), ]); if (!info || !appManifest) return; const manifest = { ...info, ...appManifest }; const { displayName: name, installLocation: path, namespaceId, catalogNamespace, itemId, catalogItemId, artifactId, appName, } = manifest; const bestId = typeof artifactId === "string" ? artifactId : appName; const launchId = [ typeof namespaceId === "string" ? namespaceId : catalogNamespace, typeof itemId === "string" ? itemId : catalogItemId, bestId, ].filter(Boolean).join(":"); return { launcher, manifest, id: bestId, name, path, launchId, } satisfies App; }; /** * Gets information about an installed Epic Games Launcher app. * * Resolves `undefined` if an app with a matching path cannot be found. * * @param path The InstallLocation of the app. */ export const getAppByPath = async (path: string) => { const [info, appManifest] = await Promise.all([ getLauncherInstalled() .then((apps) => apps.find((app) => app.installLocation === path)), getManifestByPath(path), ]); if (!info || !appManifest) return; const manifest = { ...info, ...appManifest }; const { displayName: name, installLocation, namespaceId, catalogNamespace, itemId, catalogItemId, artifactId, appName, } = manifest; const id = typeof artifactId === "string" ? artifactId : appName; const launchId = [ typeof namespaceId === "string" ? namespaceId : catalogNamespace, typeof itemId === "string" ? itemId : catalogItemId, id, ].filter(Boolean).join(":"); return { launcher, manifest, id, name, path: installLocation, launchId, } satisfies App; }; /** * Launches an Epic Games Launcher app. * * @param app The app to launch. */ export function launch(app: App): Promise; /** * Launches an Epic Games Launcher app. * * @param app The ArtifactId, AppName or InstallLocation of the app. */ export function launch(app: string): Promise; /** * Launches an Epic Games Launcher app. * * @param app The app, ArtifactId, AppName or InstallLocation of the app. */ export function launch(app: App | string): Promise; export async function launch(app: App | string): Promise { const launchId = typeof app !== "string" ? app.launchId : basename(app) === app ? (await getAppById(app))?.launchId : app; if (!launchId) return; await open( `com.epicgames.launcher://apps/${launchId}?action=launch&silent=true`, ); }