destructure @native, expose it, and add fs wrappers

This commit is contained in:
amsyarasyiq 2024-02-25 10:44:54 +08:00
parent 9de6ca830f
commit 09c0021be8
14 changed files with 99 additions and 7 deletions

View file

@ -23,6 +23,7 @@
"@swc/core": "^1.4.2",
"@types/chroma-js": "^2.4.0",
"@types/lodash": "^4.14.194",
"@types/node": "^20.11.20",
"@types/react": "18.0.35",
"@types/react-native": "0.70.6",
"esbuild": "^0.17.16",

View file

@ -15,6 +15,7 @@
alerts
assets
}
native
plugins
themes
commands

13
pnpm-lock.yaml generated
View file

@ -25,6 +25,9 @@ devDependencies:
'@types/lodash':
specifier: ^4.14.194
version: 4.14.194
'@types/node':
specifier: ^20.11.20
version: 20.11.20
'@types/react':
specifier: 18.0.35
version: 18.0.35
@ -396,6 +399,12 @@ packages:
resolution: {integrity: sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g==}
dev: true
/@types/node@20.11.20:
resolution: {integrity: sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg==}
dependencies:
undici-types: 5.26.5
dev: true
/@types/prop-types@15.7.5:
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
dev: true
@ -502,3 +511,7 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
dev: true
/undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
dev: true

View file

@ -14,7 +14,7 @@ const init = (async () => {
await import(".").then((m) => m.default());
} catch (e) {
const { ClientInfoManager } = require("@lib/native");
const { ClientInfoManager } = require("@lib/native/modules");
const stack = e instanceof Error ? e.stack : undefined;
console.log(stack ?? e?.toString?.() ?? e);

View file

@ -1,7 +1,7 @@
import { ReactNative as RN } from "@metro/common";
import { after } from "@lib/patcher";
import { getThemeFromLoader, selectTheme } from "@lib/themes";
import { ClientInfoManager, DeviceManager, BundleUpdaterManager } from "@lib/native";
import { ClientInfoManager, DeviceManager, BundleUpdaterManager } from "@lib/native/modules";
import { getAssetIDByName } from "@ui/assets";
import { showToast } from "@ui/toasts";
import settings from "@lib/settings";

73
src/lib/native/fs.ts Normal file
View file

@ -0,0 +1,73 @@
import { FileManager } from "@lib/native/modules";
/**
* Remove file from given path, currently no check for any failure
* @param path Path to the file
*/
export async function removeFile(path: string, prefix = "pyoncord/") {
return void await FileManager.removeFile("documents", `${prefix}${path}`);
}
/**
* Check if the file or directory given by the path exists
* @param path Path to the file
*/
export async function fileExists(path: string, prefix = "pyoncord/") {
return await FileManager.fileExists(`${FileManager.getConstants().DocumentsDirPath}/${prefix}${path}`);
}
/**
* A wrapper to write to a file to the documents directory
* @param path Path to the file
* @param data String data to write to the file
*/
export async function writeFile(path: string, data: string, prefix = "pyoncord/"): Promise<void> {
if (typeof data !== "string") throw new Error("Argument 'data' must be a string");
return void await FileManager.writeFile("documents", `${prefix}${path}`, data, "utf8");
}
/**
* A wrapper to read a file from the documents directory
* @param path Path to the file
* @param fallback Fallback data to return if the file doesn't exist, and will be written to the file
*/
export async function readFile(path: string, fallback?: string | null, prefix = "pyoncord/"): Promise<string> {
try {
return await FileManager.readFile(`${FileManager.getConstants().DocumentsDirPath}/${prefix}${path}`, "utf8");
} catch {
if (fallback == null) {
throw new Error(`Errored while reading ${path} doesn't exist`);
}
await writeFile(path, fallback);
return fallback;
}
}
export async function downloadFile(url: string, path: string, prefix = "pyoncord/") {
const blob = await fetch(url).then(r => r.blob());
const dataURL: string | null = await new Promise(r => {
const reader = new FileReader();
reader.onload = () => r(reader.result as unknown as string);
reader.readAsDataURL(blob);
});
let data: string;
if (dataURL == null) {
throw new Error("Failed to convert blob to data URL");
} else {
const index = dataURL.indexOf("base64,");
if (index === -1) throw new Error("dataURL does not contain base64");
data = dataURL.slice(index + 7);
}
return void await FileManager.writeFile("documents", `${prefix}${path}`, data, "base64");
}
// // thanks Rosie, doesnt work though
// export async function downloadFile(url: string, path: string, prefix = "pyoncord/") {
// const arrayBuffer = await fetch(url).then(r => r.arrayBuffer());
// const data = Buffer.from(arrayBuffer).toString("base64");
// return void await FileManager.writeFile("documents", `${prefix}${path}`, data, "base64");
// }

2
src/lib/native/index.ts Normal file
View file

@ -0,0 +1,2 @@
export * as fs from "./fs";
export * as modules from "./modules";

View file

@ -1,4 +1,4 @@
import { MMKVManager, FileManager } from "@lib/native";
import { MMKVManager, FileManager } from "@lib/native/modules";
import { ReactNative as RN } from "@metro/common";
export interface StorageBackend {

View file

@ -4,7 +4,7 @@ import { find, findByName, findByProps, findByStoreName } from "@metro/filters";
import { after, before, instead } from "@lib/patcher";
import { createFileBackend, createMMKVBackend, createStorage, wrapSync, awaitSyncWrapper } from "@lib/storage";
import logger from "@lib/logger";
import { ThemeManager } from "./native";
import { ThemeManager } from "@lib/native/modules";
import { getStoredTheme, getThemeFilePath } from "./loader";
import { Author } from "./types";

View file

@ -1,6 +1,7 @@
import { createVendettaObject } from "./vendettaObject";
import * as constants from "@lib/constants";
import * as debug from "@lib/debug";
import * as native from "@lib/native";
import * as plugins from "@lib/plugins";
import * as themes from "@lib/themes";
import * as commands from "@lib/commands";
@ -36,6 +37,7 @@ function createBunnyObject(unloads: any[]) {
assets: { ...assets },
...color,
},
native: { ...native },
plugins: utils.without({ ...plugins }, "initPlugins", "evalPlugin"),
themes: utils.without({ ...themes }, "initThemes"),
commands: utils.without({ ...commands }, "patchCommands"),

View file

@ -2,7 +2,7 @@ import { ReactNative as RN, stylesheet } from "@metro/common";
import { findByName, findByProps, findByStoreName } from "@metro/filters";
import { after } from "@lib/patcher";
import { toggleSafeMode } from "@lib/debug";
import { DeviceManager } from "@lib/native";
import { DeviceManager } from "@lib/native/modules";
import { semanticColors } from "@ui/color";
import { Button, Codeblock, ErrorBoundary as _ErrorBoundary, SafeAreaView } from "@ui/components";
import settings from "@lib/settings";

View file

@ -1,6 +1,6 @@
import { NavigationNative, clipboard } from "@metro/common";
import { removePlugin, startPlugin, stopPlugin, getSettings, fetchPlugin, BunnyPlugin } from "@lib/plugins";
import { MMKVManager } from "@lib/native";
import { MMKVManager } from "@lib/native/modules";
import { getAssetIDByName } from "@ui/assets";
import { showToast } from "@ui/toasts";
import { showConfirmationAlert } from "@ui/alerts";

View file

@ -1,7 +1,7 @@
import { clipboard } from "@metro/common";
import { Theme, applyTheme, fetchTheme, removeTheme, selectTheme, themes } from "@lib/themes";
import { useProxy } from "@lib/storage";
import { BundleUpdaterManager } from "@lib/native";
import { BundleUpdaterManager } from "@lib/native/modules";
import { getAssetIDByName } from "@ui/assets";
import { showConfirmationAlert } from "@ui/alerts";
import { showToast } from "@ui/toasts";