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