this repo has no description
1import "@moonlight-mod/web-preload";
2import { readConfig, writeConfig } from "@moonlight-mod/core/config";
3import Logger, { initLogger } from "@moonlight-mod/core/util/logger";
4import { getExtensions } from "@moonlight-mod/core/extension";
5import { loadExtensions } from "@moonlight-mod/core/extension/loader";
6import { MoonlightBranch, MoonlightNode } from "@moonlight-mod/types";
7import { IndexedDB } from "@zenfs/dom";
8import { configure } from "@zenfs/core";
9import * as fs from "@zenfs/core/promises";
10
11function getParts(path: string) {
12 if (path.startsWith("/")) path = path.substring(1);
13 return path.split("/");
14}
15
16window._moonlightBrowserInit = async () => {
17 // Set up a virtual filesystem with IndexedDB
18 await configure({
19 mounts: {
20 "/": {
21 backend: IndexedDB,
22 // eslint-disable-next-line @typescript-eslint/ban-ts-comment
23 // @ts-ignore tsc tweaking
24 storeName: "moonlight-fs"
25 }
26 }
27 });
28
29 window.moonlightFS = {
30 async readFile(path) {
31 return new Uint8Array(await fs.readFile(path));
32 },
33 async readFileString(path) {
34 const file = await this.readFile(path);
35 return new TextDecoder().decode(file);
36 },
37 async writeFile(path, data) {
38 await fs.writeFile(path, data);
39 },
40 async writeFileString(path, data) {
41 const file = new TextEncoder().encode(data);
42 await this.writeFile(path, file);
43 },
44 async unlink(path) {
45 await fs.unlink(path);
46 },
47
48 async readdir(path) {
49 return await fs.readdir(path);
50 },
51 async mkdir(path) {
52 const parts = getParts(path);
53 for (let i = 0; i < parts.length; i++) {
54 const path = this.join(...parts.slice(0, i + 1));
55 if (!(await this.exists(path))) await fs.mkdir(path);
56 }
57 },
58
59 async rmdir(path) {
60 const entries = await this.readdir(path);
61
62 for (const entry of entries) {
63 const fullPath = this.join(path, entry);
64 const isFile = await this.isFile(fullPath);
65 if (isFile) {
66 await this.unlink(fullPath);
67 } else {
68 await this.rmdir(fullPath);
69 }
70 }
71
72 await fs.rmdir(path);
73 },
74
75 async exists(path) {
76 return await fs.exists(path);
77 },
78 async isFile(path) {
79 return (await fs.stat(path)).isFile();
80 },
81
82 join(...parts) {
83 let str = parts.join("/");
84 if (!str.startsWith("/")) str = "/" + str;
85 return str;
86 },
87 dirname(path) {
88 const parts = getParts(path);
89 return "/" + parts.slice(0, parts.length - 1).join("/");
90 }
91 };
92
93 // Actual loading begins here
94 const config = await readConfig();
95 initLogger(config);
96
97 const extensions = await getExtensions();
98 const processedExtensions = await loadExtensions(extensions);
99
100 function getConfig(ext: string) {
101 const val = config.extensions[ext];
102 if (val == null || typeof val === "boolean") return undefined;
103 return val.config;
104 }
105
106 const moonlightNode: MoonlightNode = {
107 config,
108 extensions,
109 processedExtensions,
110 nativesCache: {},
111 isBrowser: true,
112
113 version: MOONLIGHT_VERSION,
114 branch: MOONLIGHT_BRANCH as MoonlightBranch,
115
116 getConfig,
117 getConfigOption: <T>(ext: string, name: string) => {
118 const config = getConfig(ext);
119 if (config == null) return undefined;
120 const option = config[name];
121 if (option == null) return undefined;
122 return option as T;
123 },
124 getNatives: () => {},
125 getLogger: (id: string) => {
126 return new Logger(id);
127 },
128
129 getMoonlightDir() {
130 return "/";
131 },
132 getExtensionDir: (ext: string) => {
133 return `/extensions/${ext}`;
134 },
135
136 writeConfig
137 };
138
139 Object.assign(window, {
140 moonlightNode
141 });
142
143 // This is set by web-preload for us
144 await window._moonlightBrowserLoad();
145};