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";
11import { NodeEventPayloads, NodeEventType } from "@moonlight-mod/types/core/event";
12import { createEventEmitter } from "@moonlight-mod/core/util/event";
13
14function getParts(path: string) {
15 if (path.startsWith("/")) path = path.substring(1);
16 return path.split("/");
17}
18
19window._moonlightBrowserInit = async () => {
20 delete window._moonlightBrowserInit;
21
22 // Set up a virtual filesystem with IndexedDB
23 await configureSingle({
24 backend: IndexedDB,
25 storeName: "moonlight-fs"
26 });
27
28 window.moonlightNodeSandboxed = {
29 fs: {
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 async isDir(path) {
82 return (await fs.stat(path)).isDirectory();
83 },
84
85 join(...parts) {
86 let str = parts.join("/");
87 if (!str.startsWith("/")) str = "/" + str;
88 return str;
89 },
90 dirname(path) {
91 const parts = getParts(path);
92 return "/" + parts.slice(0, parts.length - 1).join("/");
93 }
94 },
95 // TODO
96 addCors(url) {},
97 addBlocked(url) {}
98 };
99
100 // Actual loading begins here
101 let config = await readConfig();
102 initLogger(config);
103
104 const extensions = await getExtensions();
105 const processedExtensions = await loadExtensions(extensions);
106
107 const moonlightNode: MoonlightNode = {
108 get config() {
109 return config;
110 },
111 extensions,
112 processedExtensions,
113 nativesCache: {},
114 isBrowser: true,
115 events: createEventEmitter<NodeEventType, NodeEventPayloads>(),
116
117 version: MOONLIGHT_VERSION,
118 branch: MOONLIGHT_BRANCH as MoonlightBranch,
119
120 getConfig(ext) {
121 return getConfig(ext, config);
122 },
123 getConfigOption(ext, name) {
124 const manifest = getManifest(extensions, ext);
125 return getConfigOption(ext, name, config, manifest?.settings);
126 },
127 async setConfigOption(ext, name, value) {
128 setConfigOption(config, ext, name, value);
129 await this.writeConfig(config);
130 },
131
132 getNatives: () => {},
133 getLogger: (id: string) => {
134 return new Logger(id);
135 },
136
137 getMoonlightDir() {
138 return "/";
139 },
140 getExtensionDir: (ext: string) => {
141 return `/extensions/${ext}`;
142 },
143
144 async writeConfig(newConfig) {
145 await writeConfig(newConfig);
146 config = newConfig;
147 this.events.dispatchEvent(NodeEventType.ConfigSaved, newConfig);
148 }
149 };
150
151 Object.assign(window, {
152 moonlightNode
153 });
154
155 // This is set by web-preload for us
156 await window._moonlightWebLoad!();
157};