this repo has no description
at v1.2.0 5.4 kB view raw
1import { 2 ExtensionManifest, 3 DetectedExtension, 4 ExtensionLoadSource, 5 constants 6} from "@moonlight-mod/types"; 7import { readConfig } from "./config"; 8import { getCoreExtensionsPath, getExtensionsPath } from "./util/data"; 9import Logger from "./util/logger"; 10 11const logger = new Logger("core/extension"); 12 13async function findManifests(dir: string): Promise<string[]> { 14 const ret = []; 15 16 if (await moonlightFS.exists(dir)) { 17 for (const file of await moonlightFS.readdir(dir)) { 18 const path = moonlightFS.join(dir, file); 19 if (file === "manifest.json") { 20 ret.push(path); 21 } 22 23 if (!(await moonlightFS.isFile(path))) { 24 ret.push(...(await findManifests(path))); 25 } 26 } 27 } 28 29 return ret; 30} 31 32async function loadDetectedExtensions( 33 dir: string, 34 type: ExtensionLoadSource 35): Promise<DetectedExtension[]> { 36 const ret: DetectedExtension[] = []; 37 38 const manifests = await findManifests(dir); 39 for (const manifestPath of manifests) { 40 try { 41 if (!(await moonlightFS.exists(manifestPath))) continue; 42 const dir = moonlightFS.dirname(manifestPath); 43 44 const manifest: ExtensionManifest = JSON.parse( 45 await moonlightFS.readFileString(manifestPath) 46 ); 47 48 const webPath = moonlightFS.join(dir, "index.js"); 49 const nodePath = moonlightFS.join(dir, "node.js"); 50 const hostPath = moonlightFS.join(dir, "host.js"); 51 52 // if none exist (empty manifest) don't give a shit 53 if ( 54 !moonlightFS.exists(webPath) && 55 !moonlightFS.exists(nodePath) && 56 !moonlightFS.exists(hostPath) 57 ) { 58 continue; 59 } 60 61 const web = (await moonlightFS.exists(webPath)) 62 ? await moonlightFS.readFileString(webPath) 63 : undefined; 64 65 let url: string | undefined = undefined; 66 const urlPath = moonlightFS.join(dir, constants.repoUrlFile); 67 if ( 68 type === ExtensionLoadSource.Normal && 69 (await moonlightFS.exists(urlPath)) 70 ) { 71 url = await moonlightFS.readFileString(urlPath); 72 } 73 74 const wpModules: Record<string, string> = {}; 75 const wpModulesPath = moonlightFS.join(dir, "webpackModules"); 76 if (await moonlightFS.exists(wpModulesPath)) { 77 const wpModulesFile = await moonlightFS.readdir(wpModulesPath); 78 79 for (const wpModuleFile of wpModulesFile) { 80 if (wpModuleFile.endsWith(".js")) { 81 wpModules[wpModuleFile.replace(".js", "")] = 82 await moonlightFS.readFileString( 83 moonlightFS.join(wpModulesPath, wpModuleFile) 84 ); 85 } 86 } 87 } 88 89 ret.push({ 90 id: manifest.id, 91 manifest, 92 source: { 93 type, 94 url 95 }, 96 scripts: { 97 web, 98 webPath: web != null ? webPath : undefined, 99 webpackModules: wpModules, 100 nodePath: (await moonlightFS.exists(nodePath)) ? nodePath : undefined, 101 hostPath: (await moonlightFS.exists(hostPath)) ? hostPath : undefined 102 } 103 }); 104 } catch (e) { 105 logger.error(e, "Failed to load extension"); 106 } 107 } 108 109 return ret; 110} 111 112async function getExtensionsNative(): Promise<DetectedExtension[]> { 113 const config = await readConfig(); 114 const res = []; 115 116 res.push( 117 ...(await loadDetectedExtensions( 118 getCoreExtensionsPath(), 119 ExtensionLoadSource.Core 120 )) 121 ); 122 123 res.push( 124 ...(await loadDetectedExtensions( 125 await getExtensionsPath(), 126 ExtensionLoadSource.Normal 127 )) 128 ); 129 130 for (const devSearchPath of config.devSearchPaths ?? []) { 131 res.push( 132 ...(await loadDetectedExtensions( 133 devSearchPath, 134 ExtensionLoadSource.Developer 135 )) 136 ); 137 } 138 139 return res; 140} 141 142async function getExtensionsBrowser(): Promise<DetectedExtension[]> { 143 const ret: DetectedExtension[] = []; 144 145 const coreExtensionsFs: Record<string, string> = JSON.parse( 146 // @ts-expect-error shut up 147 _moonlight_coreExtensionsStr 148 ); 149 const coreExtensions = Array.from( 150 new Set(Object.keys(coreExtensionsFs).map((x) => x.split("/")[0])) 151 ); 152 153 for (const ext of coreExtensions) { 154 if (!coreExtensionsFs[`${ext}/index.js`]) continue; 155 const manifest = JSON.parse(coreExtensionsFs[`${ext}/manifest.json`]); 156 const web = coreExtensionsFs[`${ext}/index.js`]; 157 158 const wpModules: Record<string, string> = {}; 159 const wpModulesPath = `${ext}/webpackModules`; 160 for (const wpModuleFile of Object.keys(coreExtensionsFs)) { 161 if (wpModuleFile.startsWith(wpModulesPath)) { 162 wpModules[ 163 wpModuleFile.replace(wpModulesPath + "/", "").replace(".js", "") 164 ] = coreExtensionsFs[wpModuleFile]; 165 } 166 } 167 168 ret.push({ 169 id: manifest.id, 170 manifest, 171 source: { 172 type: ExtensionLoadSource.Core 173 }, 174 scripts: { 175 web, 176 webpackModules: wpModules 177 } 178 }); 179 } 180 181 if (await moonlightFS.exists("/extensions")) { 182 ret.push( 183 ...(await loadDetectedExtensions( 184 "/extensions", 185 ExtensionLoadSource.Normal 186 )) 187 ); 188 } 189 190 return ret; 191} 192 193export async function getExtensions(): Promise<DetectedExtension[]> { 194 webPreload: { 195 return moonlightNode.extensions; 196 } 197 198 browser: { 199 return await getExtensionsBrowser(); 200 } 201 202 nodeTarget: { 203 return await getExtensionsNative(); 204 } 205 206 throw new Error("Called getExtensions() outside of node-preload/web-preload"); 207}