this repo has no description

Abstract FS for browser

Changed files
+289 -406
packages
browser
src
core
core-extensions
src
moonbase
node-preload
src
types
+18 -15
packages/browser/src/index.ts
···
import Logger, { initLogger } from "@moonlight-mod/core/util/logger";
import { getExtensions } from "@moonlight-mod/core/extension";
import { loadExtensions } from "@moonlight-mod/core/extension/loader";
-
import {
-
MoonlightBranch,
-
MoonlightBrowserFS,
-
MoonlightNode
-
} from "@moonlight-mod/types";
+
import { MoonlightBranch, MoonlightNode } from "@moonlight-mod/types";
import { IndexedDB } from "@zenfs/dom";
import { configure } from "@zenfs/core";
import * as fs from "@zenfs/core/promises";
+
function getParts(path: string) {
+
if (path.startsWith("/")) path = path.substring(1);
+
return path.split("/");
+
}
+
window._moonlightBrowserInit = async () => {
// Set up a virtual filesystem with IndexedDB
await configure({
···
}
});
-
const browserFS: MoonlightBrowserFS = {
+
window._moonlightBrowserFS = {
async readFile(path) {
return new Uint8Array(await fs.readFile(path));
+
},
+
async readFileString(path) {
+
const file = await this.readFile(path);
+
return new TextDecoder().decode(file);
},
async writeFile(path, data) {
await fs.writeFile(path, data);
},
+
async writeFileString(path, data) {
+
const file = new TextEncoder().encode(data);
+
await this.writeFile(path, file);
+
},
async unlink(path) {
await fs.unlink(path);
},
···
return await fs.readdir(path);
},
async mkdir(path) {
-
const parts = this.parts(path);
+
const parts = getParts(path);
for (let i = 0; i < parts.length; i++) {
const path = this.join(...parts.slice(0, i + 1));
if (!(await this.exists(path))) await fs.mkdir(path);
···
return str;
},
dirname(path) {
-
const parts = this.parts(path);
+
const parts = getParts(path);
return "/" + parts.slice(0, parts.length - 1).join("/");
-
},
-
parts(path) {
-
if (path.startsWith("/")) path = path.substring(1);
-
return path.split("/");
}
};
-
Object.assign(window, {
-
_moonlightBrowserFS: browserFS
-
});
// Actual loading begins here
const config = await readConfig();
···
extensions,
processedExtensions,
nativesCache: {},
+
fs: window._moonlightBrowserFS,
version: MOONLIGHT_VERSION,
branch: MOONLIGHT_BRANCH as MoonlightBranch,
-3
packages/core-extensions/src/moonbase/consts.ts
···
-
export const githubRepo = "moonlight-mod/moonlight";
-
export const nightlyRefUrl = "https://moonlight-mod.github.io/moonlight/ref";
-
export const userAgent = `moonlight/${moonlightNode.version} (https://github.com/moonlight-mod/moonlight)`;
+104
packages/core-extensions/src/moonbase/native.ts
···
+
import { MoonlightBranch } from "@moonlight-mod/types";
+
import type { MoonbaseNatives, RepositoryManifest } from "./types";
+
import extractAsar from "@moonlight-mod/core/asar";
+
import { repoUrlFile } from "@moonlight-mod/types/constants";
+
+
export const githubRepo = "moonlight-mod/moonlight";
+
export const nightlyRefUrl = "https://moonlight-mod.github.io/moonlight/ref";
+
export const userAgent = `moonlight/${moonlightNode.version} (https://github.com/moonlight-mod/moonlight)`;
+
+
export default function getNatives(): MoonbaseNatives {
+
const fs = moonlightNode.fs;
+
const logger = moonlightNode.getLogger("moonbase/natives");
+
+
return {
+
async checkForMoonlightUpdate() {
+
try {
+
if (moonlightNode.branch === MoonlightBranch.STABLE) {
+
const req = await fetch(
+
`https://api.github.com/repos/${githubRepo}/releases/latest?_=${Date.now()}`,
+
{
+
headers: {
+
"User-Agent": userAgent
+
}
+
}
+
);
+
const json: { name: string } = await req.json();
+
return json.name !== moonlightNode.version ? json.name : null;
+
} else if (moonlightNode.branch === MoonlightBranch.NIGHTLY) {
+
const req = await fetch(`${nightlyRefUrl}?_=${Date.now()}`, {
+
headers: {
+
"User-Agent": userAgent
+
}
+
});
+
const ref = (await req.text()).split("\n")[0];
+
return ref !== moonlightNode.version ? ref : null;
+
}
+
+
return null;
+
} catch (e) {
+
logger.error("Error checking for moonlight update", e);
+
return null;
+
}
+
},
+
+
async fetchRepositories(repos) {
+
const ret: Record<string, RepositoryManifest[]> = {};
+
+
for (const repo of repos) {
+
try {
+
const req = await fetch(repo, {
+
headers: {
+
"User-Agent": userAgent
+
}
+
});
+
const json = await req.json();
+
ret[repo] = json;
+
} catch (e) {
+
logger.error(`Error fetching repository ${repo}`, e);
+
}
+
}
+
+
return ret;
+
},
+
+
async installExtension(manifest, url, repo) {
+
const req = await fetch(url, {
+
headers: {
+
"User-Agent": userAgent
+
}
+
});
+
+
const dir = moonlightNode.getExtensionDir(manifest.id);
+
// remake it in case of updates
+
if (await fs.exists(dir)) await fs.rmdir(dir);
+
await fs.mkdir(dir);
+
+
const buffer = await req.arrayBuffer();
+
const files = extractAsar(buffer);
+
for (const [file, buf] of Object.entries(files)) {
+
const fullFile = fs.join(dir, file);
+
const fullDir = fs.dirname(fullFile);
+
+
if (!(await fs.exists(fullDir))) await fs.mkdir(fullDir);
+
await fs.writeFile(fs.join(dir, file), buf);
+
}
+
+
await fs.writeFileString(fs.join(dir, repoUrlFile), repo);
+
},
+
+
async deleteExtension(id) {
+
const dir = moonlightNode.getExtensionDir(id);
+
await fs.rmdir(dir);
+
},
+
+
getExtensionConfig(id, key) {
+
const config = moonlightNode.config.extensions[id];
+
if (typeof config === "object") {
+
return config.config?.[key];
+
}
+
+
return undefined;
+
}
+
};
+
}
+2 -113
packages/core-extensions/src/moonbase/node.ts
···
-
import { MoonbaseNatives, RepositoryManifest } from "./types";
-
import fs from "fs";
-
import path from "path";
-
import extractAsar from "@moonlight-mod/core/asar";
-
import { repoUrlFile } from "@moonlight-mod/types/constants";
-
import { githubRepo, userAgent, nightlyRefUrl } from "./consts";
-
import { MoonlightBranch } from "types/src";
-
-
const logger = moonlightNode.getLogger("moonbase");
-
-
async function checkForMoonlightUpdate() {
-
try {
-
if (moonlightNode.branch === MoonlightBranch.STABLE) {
-
const req = await fetch(
-
`https://api.github.com/repos/${githubRepo}/releases/latest?_=${Date.now()}`,
-
{
-
headers: {
-
"User-Agent": userAgent
-
}
-
}
-
);
-
const json: { name: string } = await req.json();
-
return json.name !== moonlightNode.version ? json.name : null;
-
} else if (moonlightNode.branch === MoonlightBranch.NIGHTLY) {
-
const req = await fetch(`${nightlyRefUrl}?_=${Date.now()}`, {
-
headers: {
-
"User-Agent": userAgent
-
}
-
});
-
const ref = (await req.text()).split("\n")[0];
-
return ref !== moonlightNode.version ? ref : null;
-
}
-
-
return null;
-
} catch (e) {
-
logger.error("Error checking for moonlight update", e);
-
return null;
-
}
-
}
-
-
async function fetchRepositories(repos: string[]) {
-
const ret: Record<string, RepositoryManifest[]> = {};
-
-
for (const repo of repos) {
-
try {
-
const req = await fetch(repo, {
-
headers: {
-
"User-Agent": userAgent
-
}
-
});
-
const json = await req.json();
-
ret[repo] = json;
-
} catch (e) {
-
logger.error(`Error fetching repository ${repo}`, e);
-
}
-
}
-
-
return ret;
-
}
-
-
async function installExtension(
-
manifest: RepositoryManifest,
-
url: string,
-
repo: string
-
) {
-
const req = await fetch(url, {
-
headers: {
-
"User-Agent": userAgent
-
}
-
});
-
-
const dir = moonlightNode.getExtensionDir(manifest.id);
-
// remake it in case of updates
-
if (fs.existsSync(dir)) fs.rmdirSync(dir, { recursive: true });
-
fs.mkdirSync(dir, { recursive: true });
-
-
const buffer = await req.arrayBuffer();
-
const files = extractAsar(buffer);
-
for (const [file, buf] of Object.entries(files)) {
-
const nodeBuf = Buffer.from(buf);
-
const fullFile = path.join(dir, file);
-
const fullDir = path.dirname(fullFile);
-
-
if (!fs.existsSync(fullDir)) fs.mkdirSync(fullDir, { recursive: true });
-
fs.writeFileSync(path.join(dir, file), nodeBuf);
-
}
-
-
fs.writeFileSync(path.join(dir, repoUrlFile), repo);
-
}
-
-
async function deleteExtension(id: string) {
-
const dir = moonlightNode.getExtensionDir(id);
-
fs.rmdirSync(dir, { recursive: true });
-
}
-
-
function getExtensionConfig(id: string, key: string): any {
-
const config = moonlightNode.config.extensions[id];
-
if (typeof config === "object") {
-
return config.config?.[key];
-
}
-
-
return undefined;
-
}
-
-
const exports: MoonbaseNatives = {
-
checkForMoonlightUpdate,
-
fetchRepositories,
-
installExtension,
-
deleteExtension,
-
getExtensionConfig
-
};
-
-
module.exports = exports;
+
import getNatives from "./native";
+
module.exports = getNatives();
+6 -104
packages/core-extensions/src/moonbase/webpackModules/stores.ts
···
-
import {
-
Config,
-
ExtensionLoadSource,
-
MoonlightBranch
-
} from "@moonlight-mod/types";
-
import {
-
ExtensionState,
-
MoonbaseExtension,
-
MoonbaseNatives,
-
RepositoryManifest
-
} from "../types";
+
import { Config, ExtensionLoadSource } from "@moonlight-mod/types";
+
import { ExtensionState, MoonbaseExtension, MoonbaseNatives } from "../types";
import { Store } from "@moonlight-mod/wp/discord/packages/flux";
import Dispatcher from "@moonlight-mod/wp/discord/Dispatcher";
-
import extractAsar from "@moonlight-mod/core/asar";
-
import { repoUrlFile } from "@moonlight-mod/types/constants";
-
import { githubRepo, userAgent, nightlyRefUrl } from "../consts";
+
import getNatives from "../native";
const logger = moonlight.getLogger("moonbase");
let natives: MoonbaseNatives = moonlight.getNatives("moonbase");
-
if (window._moonlightBrowserFS != null) {
-
const browserFS = window._moonlightBrowserFS!;
-
natives = {
-
checkForMoonlightUpdate: async () => {
-
try {
-
if (moonlight.branch === MoonlightBranch.STABLE) {
-
const req = await fetch(
-
`https://api.github.com/repos/${githubRepo}/releases/latest`,
-
{
-
headers: {
-
"User-Agent": userAgent
-
}
-
}
-
);
-
const json: { name: string } = await req.json();
-
return json.name !== moonlight.version ? json.name : null;
-
} else if (moonlight.branch === MoonlightBranch.NIGHTLY) {
-
const req = await fetch(nightlyRefUrl, {
-
headers: {
-
"User-Agent": userAgent
-
}
-
});
-
const ref = (await req.text()).split("\n")[0];
-
return ref !== moonlight.version ? ref : null;
-
}
-
-
return null;
-
} catch (e) {
-
logger.error("Error checking for moonlight update", e);
-
return null;
-
}
-
},
-
-
fetchRepositories: async (repos) => {
-
const ret: Record<string, RepositoryManifest[]> = {};
-
-
for (const repo of repos) {
-
try {
-
const req = await fetch(repo);
-
const json = await req.json();
-
ret[repo] = json;
-
} catch (e) {
-
logger.error(`Error fetching repository ${repo}`, e);
-
}
-
}
-
-
return ret;
-
},
-
installExtension: async (manifest, url, repo) => {
-
const req = await fetch(url);
-
const buffer = await req.arrayBuffer();
-
-
if (await browserFS.exists("/extensions/" + manifest.id)) {
-
await browserFS.rmdir("/extensions/" + manifest.id);
-
}
-
-
const files = extractAsar(buffer);
-
for (const [file, data] of Object.entries(files)) {
-
const path =
-
"/extensions/" +
-
manifest.id +
-
(file.startsWith("/") ? file : `/${file}`);
-
await browserFS.mkdir(browserFS.dirname(path));
-
await browserFS.writeFile(path, data);
-
}
-
-
await browserFS.writeFile(
-
`/extensions/${manifest.id}/` + repoUrlFile,
-
new TextEncoder().encode(repo)
-
);
-
},
-
deleteExtension: async (id) => {
-
browserFS.rmdir("/extensions/" + id);
-
},
-
getExtensionConfig: (id, key) => {
-
const config = moonlightNode.config.extensions[id];
-
if (typeof config === "object") {
-
return config.config?.[key];
-
}
-
-
return undefined;
-
}
-
};
-
}
+
if (!natives) natives = getNatives();
class MoonbaseSettingsStore extends Store<any> {
private origConfig: Config;
···
writeConfig() {
this.submitting = true;
-
try {
-
moonlightNode.writeConfig(this.config);
-
this.origConfig = this.clone(this.config);
-
} catch (e) {
-
logger.error("Error writing config", e);
-
}
+
moonlightNode.writeConfig(this.config);
+
this.origConfig = this.clone(this.config);
this.submitting = false;
this.modified = false;
+26 -43
packages/core/src/config.ts
···
import { Config } from "@moonlight-mod/types";
-
import requireImport from "./util/import";
import { getConfigPath } from "./util/data";
+
import getFS from "./fs";
+
import Logger from "./util/logger";
+
+
const logger = new Logger("core/config");
const defaultConfig: Config = {
extensions: {
···
repositories: ["https://moonlight-mod.github.io/extensions-dist/repo.json"]
};
-
export function writeConfig(config: Config) {
-
browser: {
-
const enc = new TextEncoder().encode(JSON.stringify(config, null, 2));
-
window._moonlightBrowserFS!.writeFile("/config.json", enc);
-
return;
+
export async function writeConfig(config: Config) {
+
try {
+
const fs = getFS();
+
const configPath = await getConfigPath();
+
await fs.writeFileString(configPath, JSON.stringify(config, null, 2));
+
} catch (e) {
+
logger.error("Failed to write config", e);
}
-
-
nodeTarget: {
-
const fs = requireImport("fs");
-
const configPath = getConfigPath();
-
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
-
return;
-
}
-
-
throw new Error("Called writeConfig() in an impossible environment");
}
export async function readConfig(): Promise<Config> {
···
return moonlightNode.config;
}
-
browser: {
-
if (await window._moonlightBrowserFS!.exists("/config.json")) {
-
const file = await window._moonlightBrowserFS!.readFile("/config.json");
-
const configStr = new TextDecoder().decode(file);
-
let config: Config = JSON.parse(configStr);
+
const fs = getFS();
+
const configPath = await getConfigPath();
+
if (!(await fs.exists(configPath))) {
+
await writeConfig(defaultConfig);
+
return defaultConfig;
+
} else {
+
try {
+
let config: Config = JSON.parse(await fs.readFileString(configPath));
+
// Assign the default values if they don't exist (newly added)
config = { ...defaultConfig, ...config };
-
writeConfig(config);
+
await writeConfig(config);
return config;
-
} else {
-
writeConfig(defaultConfig);
-
return defaultConfig;
-
}
-
}
-
-
nodeTarget: {
-
const fs = requireImport("fs");
-
const configPath = getConfigPath();
-
-
if (!fs.existsSync(configPath)) {
-
writeConfig(defaultConfig);
+
} catch (e) {
+
logger.error("Failed to read config, falling back to defaults", e);
+
// We don't want to write the default config here - if a user is manually
+
// editing their config and messes it up, we'll delete it all instead of
+
// letting them fix it
return defaultConfig;
}
-
-
let config: Config = JSON.parse(fs.readFileSync(configPath, "utf8"));
-
-
// Assign the default values if they don't exist (newly added)
-
config = { ...defaultConfig, ...config };
-
writeConfig(config);
-
-
return config;
}
-
-
throw new Error("Called readConfig() in an impossible environment");
}
+11 -76
packages/core/src/extension.ts
···
ExtensionManifest,
DetectedExtension,
ExtensionLoadSource,
-
constants
+
constants,
+
MoonlightFS
} from "@moonlight-mod/types";
import { readConfig } from "./config";
-
import requireImport from "./util/import";
import { getCoreExtensionsPath, getExtensionsPath } from "./util/data";
import Logger from "./util/logger";
+
import getFS from "./fs";
const logger = new Logger("core/extension");
-
// This is kinda duplicated from the browser FS type but idc
-
interface MoonlightFSWrapper {
-
readdir(path: string): Promise<string[]>;
-
exists(path: string): Promise<boolean>;
-
isFile(path: string): Promise<boolean>;
-
readFile(path: string): Promise<string>;
-
join(...parts: string[]): string;
-
dirname(path: string): string;
-
}
-
-
function getFS(): MoonlightFSWrapper {
-
browser: {
-
const fs = window._moonlightBrowserFS!;
-
return {
-
async readdir(path) {
-
return await fs.readdir(path);
-
},
-
async exists(path) {
-
return await fs.exists(path);
-
},
-
async isFile(path) {
-
return await fs.isFile(path);
-
},
-
async readFile(path) {
-
const buf = await fs.readFile(path);
-
const text = new TextDecoder().decode(buf);
-
return text;
-
},
-
join(...parts) {
-
return fs.join(...parts);
-
},
-
dirname(path) {
-
return fs.dirname(path);
-
}
-
};
-
}
-
-
const fs = requireImport("fs");
-
const path = requireImport("path");
-
-
return {
-
async readdir(path) {
-
return fs.readdirSync(path);
-
},
-
async exists(path) {
-
return fs.existsSync(path);
-
},
-
async isFile(path) {
-
return fs.statSync(path).isFile();
-
},
-
async readFile(path) {
-
return fs.readFileSync(path, "utf8");
-
},
-
join(...parts) {
-
return path.join(...parts);
-
},
-
dirname(dir) {
-
return path.dirname(dir);
-
}
-
};
-
}
-
-
async function findManifests(
-
fs: MoonlightFSWrapper,
-
dir: string
-
): Promise<string[]> {
+
async function findManifests(fs: MoonlightFS, dir: string): Promise<string[]> {
const ret = [];
if (await fs.exists(dir)) {
···
}
async function loadDetectedExtensions(
-
fs: MoonlightFSWrapper,
+
fs: MoonlightFS,
dir: string,
type: ExtensionLoadSource
): Promise<DetectedExtension[]> {
···
const dir = fs.dirname(manifestPath);
const manifest: ExtensionManifest = JSON.parse(
-
await fs.readFile(manifestPath)
+
await fs.readFileString(manifestPath)
);
const level = manifest.apiLevel ?? 1;
if (level !== constants.apiLevel) {
···
}
const web = (await fs.exists(webPath))
-
? await fs.readFile(webPath)
+
? await fs.readFileString(webPath)
: undefined;
let url: string | undefined = undefined;
const urlPath = fs.join(dir, constants.repoUrlFile);
if (type === ExtensionLoadSource.Normal && (await fs.exists(urlPath))) {
-
url = await fs.readFile(urlPath);
+
url = await fs.readFileString(urlPath);
}
const wpModules: Record<string, string> = {};
···
for (const wpModuleFile of wpModulesFile) {
if (wpModuleFile.endsWith(".js")) {
-
wpModules[wpModuleFile.replace(".js", "")] = await fs.readFile(
-
fs.join(wpModulesPath, wpModuleFile)
-
);
+
wpModules[wpModuleFile.replace(".js", "")] =
+
await fs.readFileString(fs.join(wpModulesPath, wpModuleFile));
}
}
}
···
res.push(
...(await loadDetectedExtensions(
fs,
-
getExtensionsPath(),
+
await getExtensionsPath(),
ExtensionLoadSource.Normal
))
);
+56
packages/core/src/fs.ts
···
+
import { MoonlightFS } from "types/src";
+
import requireImport from "./util/import";
+
+
export default function getFS(): MoonlightFS {
+
browser: {
+
return window._moonlightBrowserFS!;
+
}
+
+
nodeTarget: {
+
const fs = requireImport("fs");
+
const path = requireImport("path");
+
+
return {
+
async readFile(path) {
+
const file = fs.readFileSync(path);
+
return new Uint8Array(file);
+
},
+
async readFileString(path) {
+
return fs.readFileSync(path, "utf8");
+
},
+
async writeFile(path, data) {
+
fs.writeFileSync(path, Buffer.from(data));
+
},
+
async writeFileString(path, data) {
+
fs.writeFileSync(path, data, "utf8");
+
},
+
async unlink(path) {
+
fs.unlinkSync(path);
+
},
+
+
async readdir(path) {
+
return fs.readdirSync(path);
+
},
+
async mkdir(path) {
+
fs.mkdirSync(path, { recursive: true });
+
},
+
async rmdir(path) {
+
fs.rmSync(path, { recursive: true });
+
},
+
+
async exists(path) {
+
return fs.existsSync(path);
+
},
+
async isFile(path) {
+
return fs.statSync(path).isFile();
+
},
+
+
join(...parts) {
+
return path.join(...parts);
+
},
+
dirname(dir) {
+
return path.dirname(dir);
+
}
+
};
+
}
+
}
+30 -26
packages/core/src/util/data.ts
···
import { constants } from "@moonlight-mod/types";
-
import requireImport from "./import";
+
import getFS from "../fs";
+
+
export async function getMoonlightDir() {
+
browser: {
+
return "/";
+
}
-
export function getMoonlightDir(): string {
const electron = require("electron");
-
const fs = requireImport("fs");
-
const path = requireImport("path");
+
const fs = getFS();
let appData = "";
injector: {
···
appData = electron.ipcRenderer.sendSync(constants.ipcGetAppData);
}
-
const dir = path.join(appData, "moonlight-mod");
-
if (!fs.existsSync(dir)) fs.mkdirSync(dir);
+
const dir = fs.join(appData, "moonlight-mod");
+
if (!(await fs.exists(dir))) await fs.mkdir(dir);
return dir;
}
···
version: string;
};
-
export function getConfigPath(): string {
-
const dir = getMoonlightDir();
-
const fs = requireImport("fs");
-
const path = requireImport("path");
+
export async function getConfigPath() {
+
browser: {
+
return "/config.json";
+
}
+
+
const fs = getFS();
+
const dir = await getMoonlightDir();
let configPath = "";
-
const buildInfoPath = path.join(process.resourcesPath, "build_info.json");
-
if (!fs.existsSync(buildInfoPath)) {
-
configPath = path.join(dir, "desktop.json");
+
const buildInfoPath = fs.join(process.resourcesPath, "build_info.json");
+
if (!(await fs.exists(buildInfoPath))) {
+
configPath = fs.join(dir, "desktop.json");
} else {
const buildInfo: BuildInfo = JSON.parse(
-
fs.readFileSync(buildInfoPath, "utf8")
+
await fs.readFileString(buildInfoPath)
);
-
configPath = path.join(dir, buildInfo.releaseChannel + ".json");
+
configPath = fs.join(dir, buildInfo.releaseChannel + ".json");
}
return configPath;
}
-
function getPathFromMoonlight(...names: string[]): string {
-
const dir = getMoonlightDir();
-
const fs = requireImport("fs");
-
const path = requireImport("path");
+
async function getPathFromMoonlight(...names: string[]) {
+
const dir = await getMoonlightDir();
+
const fs = getFS();
-
const target = path.join(dir, ...names);
-
if (!fs.existsSync(target)) fs.mkdirSync(target);
+
const target = fs.join(dir, ...names);
+
if (!(await fs.exists(target))) await fs.mkdir(target);
return target;
}
-
export function getExtensionsPath(): string {
-
return getPathFromMoonlight(constants.extensionsDir);
+
export async function getExtensionsPath() {
+
return await getPathFromMoonlight(constants.extensionsDir);
}
export function getCoreExtensionsPath(): string {
-
const path = requireImport("path");
-
const a = path.join(__dirname, constants.coreExtensionsDir);
-
return a;
+
const fs = getFS();
+
return fs.join(__dirname, constants.coreExtensionsDir);
}
+8 -5
packages/node-preload/src/index.ts
···
import { webFrame, ipcRenderer, contextBridge } from "electron";
-
import fs from "fs";
-
import path from "path";
+
import fs from "node:fs";
+
import path from "node:path";
import { readConfig, writeConfig } from "@moonlight-mod/core/config";
import { constants, MoonlightBranch } from "@moonlight-mod/types";
···
loadExtensions,
loadProcessedExtensions
} from "@moonlight-mod/core/extension/loader";
+
import getFS from "@moonlight-mod/core/fs";
async function injectGlobals() {
const config = await readConfig();
initLogger(config);
const extensions = await getExtensions();
const processedExtensions = await loadExtensions(extensions);
+
const moonlightDir = await getMoonlightDir();
+
const extensionsPath = await getExtensionsPath();
function getConfig(ext: string) {
const val = config.extensions[ext];
···
extensions,
processedExtensions,
nativesCache: {},
+
fs: getFS(),
version: MOONLIGHT_VERSION,
branch: MOONLIGHT_BRANCH as MoonlightBranch,
···
},
getMoonlightDir() {
-
return getMoonlightDir();
+
return moonlightDir;
},
getExtensionDir: (ext: string) => {
-
const extPath = getExtensionsPath();
-
return path.join(extPath, ext);
+
return path.join(extensionsPath, ext);
},
writeConfig
};
+17
packages/types/src/fs.ts
···
+
export type MoonlightFS = {
+
readFile: (path: string) => Promise<Uint8Array>;
+
readFileString: (path: string) => Promise<string>;
+
writeFile: (path: string, data: Uint8Array) => Promise<void>;
+
writeFileString: (path: string, data: string) => Promise<void>;
+
unlink: (path: string) => Promise<void>;
+
+
readdir: (path: string) => Promise<string[]>;
+
mkdir: (path: string) => Promise<void>;
+
rmdir: (path: string) => Promise<void>;
+
+
exists: (path: string) => Promise<boolean>;
+
isFile: (path: string) => Promise<boolean>;
+
+
join: (...parts: string[]) => string;
+
dirname: (path: string) => string;
+
};
+8 -19
packages/types/src/globals.ts
···
import type EventEmitter from "events";
import type LunAST from "@moonlight-mod/lunast";
import type Moonmap from "@moonlight-mod/moonmap";
-
import { EventPayloads, EventType, MoonlightEventEmitter } from "./core/event";
+
import type {
+
EventPayloads,
+
EventType,
+
MoonlightEventEmitter
+
} from "./core/event";
+
import type { MoonlightFS } from "./fs";
export type MoonlightHost = {
asarPath: string;
···
extensions: DetectedExtension[];
processedExtensions: ProcessedExtensions;
nativesCache: Record<string, any>;
+
fs: MoonlightFS;
version: string;
branch: MoonlightBranch;
···
getMoonlightDir: () => string;
getExtensionDir: (ext: string) => string;
-
writeConfig: (config: Config) => void;
-
};
-
-
export type MoonlightBrowserFS = {
-
readFile: (path: string) => Promise<Uint8Array>;
-
writeFile: (path: string, data: Uint8Array) => Promise<void>;
-
unlink: (path: string) => Promise<void>;
-
-
readdir: (path: string) => Promise<string[]>;
-
mkdir: (path: string) => Promise<void>;
-
rmdir: (path: string) => Promise<void>;
-
-
exists: (path: string) => Promise<boolean>;
-
isFile: (path: string) => Promise<boolean>;
-
-
join: (...parts: string[]) => string;
-
dirname: (path: string) => string;
-
parts: (path: string) => string[];
+
writeConfig: (config: Config) => Promise<void>;
};
export type MoonlightWeb = {
+3 -2
packages/types/src/index.ts
···
/// <reference types="./mappings" />
/* eslint-disable no-var */
+
import { MoonlightFS } from "./fs";
import {
-
MoonlightBrowserFS,
MoonlightEnv,
MoonlightHost,
MoonlightNode,
···
export * from "./globals";
export * from "./logger";
export * as constants from "./constants";
+
export * from "./fs";
export type { AST } from "@moonlight-mod/lunast";
export { ModuleExport, ModuleExportType } from "@moonlight-mod/moonmap";
···
var _moonlightBrowserInit: () => Promise<void>;
var _moonlightBrowserLoad: () => Promise<void>;
-
var _moonlightBrowserFS: MoonlightBrowserFS | undefined;
+
var _moonlightBrowserFS: MoonlightFS;
}