Compare commits

..

No commits in common. 'master' and 'master' have entirely different histories.

@ -3,7 +3,6 @@
"singleQuote": false, "singleQuote": false,
"semi": true, "semi": true,
"bracketSpacing": true, "bracketSpacing": true,
"trailingComma": "none",
"overrides": [ "overrides": [
{ {
"files": "*.js", "files": "*.js",
@ -12,4 +11,4 @@
} }
} }
] ]
} }

@ -1,3 +0,0 @@
{
"presets": ["@babel/preset-flow", "@babel/preset-react"]
}

@ -1,22 +0,0 @@
import esbuild from "esbuild";
import babel from "esbuild-plugin-babel";
(async () => {
try {
await esbuild.build({
entryPoints: ["src/index.js"],
bundle: true,
minify: true,
format: "iife",
target: "es2021",
outfile: "dist/build.js",
plugins: [babel()]
});
console.log("Build succeeded!");
process.exit(0);
} catch (e) {
console.error(e);
console.log("Build failed!");
process.exit(1);
}
})(); //IIFE to shutup lsp

@ -1,25 +1,26 @@
{ {
"name": "demoncord", "name": "demoncord",
"version": "0.0.1-indev", "version": "0.0.1-indev",
"description": "a devilesque client mod 😈", "description": "a devilesque client mod 😈",
"main": "src/index.js", "main": "src/index.js",
"scripts": { "scripts": {
"build": "node build.mjs", "build": "rollup --config rollup.config.js",
"flow": "flow" "flow": "flow"
}, },
"author": "Drake", "author": "Drake",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"devDependencies": { "devDependencies": {
"@babel/core": "^7.17.8", "@rollup/plugin-commonjs": "^21.0.1",
"@babel/preset-flow": "^7.16.7", "@rollup/plugin-node-resolve": "^13.1.3",
"@babel/preset-react": "^7.16.7", "demonpatcher": "^0.1.0",
"esbuild": "^0.14.27", "esbuild": "^0.14.11",
"esbuild-plugin-babel": "^0.2.3", "flow-bin": "^0.169.0",
"flow-bin": "^0.169.0", "flow-remove-types": "^2.169.0",
"flow-remove-types": "^2.174.1", "idb-keyval": "^6.0.3",
"idb-keyval": "^6.1.0", "rollup": "^2.63.0",
"react": "^17.0.2", "rollup-plugin-esbuild": "^4.8.2",
"react-dom": "^17.0.2", "rollup-plugin-flow": "^1.1.1",
"simian": "^1.4.3" "rollup-plugin-uglify": "^6.0.4",
} "simian": "^1.4.3"
}
} }

File diff suppressed because it is too large Load Diff

@ -0,0 +1,14 @@
import flow from "rollup-plugin-flow";
import { minify } from "rollup-plugin-esbuild";
import { nodeResolve } from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import { defineConfig } from "rollup";
export default defineConfig({
input: "src/index.js",
plugins: [flow(), commonjs(), nodeResolve(), minify()],
output: {
file: "dist/build.js",
format: "iife",
},
});

3
shims/react.js vendored

@ -1,3 +0,0 @@
import { React } from "../src/api/common.js";
export { React };

@ -1,18 +1,16 @@
// @flow // @flow
const commandsSym = Symbol("__commands"); const commandsSym = Symbol("__commands");
function init(obj: Object) { function init(obj: Object) {
const { after } = window.demon.require("patcher") obj.demon[commandsSym] = {};
const { findByProps } = window.demon.require("webpack") obj.demon.patcher.after(
window.demonCommands = {}
window.demonCommands[commandsSym] = {};
after(
"sendMessage", "sendMessage",
findByProps("sendMessage"), obj.demon.webpack.findByProps("sendMessage"),
(args, otherRes) => { (args, otherRes) => {
let res; let res;
for (const key of Reflect.ownKeys(window.demonCommands[commandsSym])) { for (const key of Reflect.ownKeys(obj.demon[commandsSym])) {
let command = window.demonCommands[commandsSym][key]; let command = obj.demon[commandsSym][key];
if (args[1].content.split(" ")[0] === ">" + command.name) { if (args[1].content.split(" ")[0] === ">" + command.name) {
res = command.callback(args); res = command.callback(args);
break; break;
@ -30,16 +28,16 @@ function init(obj: Object) {
// } // }
function add(command: { function add(command: {
name: string, name: string,
callback: (args: Array<any>) => string callback: (args: Array<any>) => string,
}): () => void { }): () => void {
let sym = Symbol(command.name); let sym = Symbol(command.name);
window.demonCommands[commandsSym][sym] = command; window.demon[commandsSym][sym] = command;
return () => { return () => {
delete window.demonCommands[commandsSym][sym]; delete window.demon[commandsSym][sym];
}; };
} }
export default { export default {
add: add, add: add,
init: init init: init,
}; };

@ -1,18 +1,18 @@
// @flow // @flow
import webpack from "./webpack.js"; import webpack from "./webpack.js"
import * as idb from "idb-keyval"; import * as idb from "idb-keyval";
const common: { React: Object, ReactDOM: Object } = { const common: {React: Object, ReactDOM: Object} = {
React: webpack.findByProps( React: webpack.findByProps(
"__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED", "__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED",
"createElement" "createElement"
), ),
ReactDOM: webpack.findByProps( ReactDOM: webpack.findByProps(
"__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED", "__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED",
"hydrate" "hydrate"
), ),
idb_keyval: idb "idb_keyval": idb
}; }
export default common; export default common;

@ -1,56 +0,0 @@
// @flow
//TODO: proper typing
//TODO: use webpack to find
//TODO: funny sink code
//(() => {
// const raw = findAll(
// (m) =>
// typeof m === "object" &&
// Object.values(m).length > 0 &&
// Object.values(m).every((v) => typeof v === "string")
// );
// const map = new Map();
// for (const m of raw)
// for (const [k, v] of Object.entries(m))
// if (map.has(k)) map.get(k).push(v);
// else map.set(k, [v]);
// return map;
//})();
function getAllClasses() {
return document.styleSheets[0].rules || document.styleSheets[0].cssRules;
}
function getClassListByName(className) {
const classes = getAllClasses();
return classes;
}
//how to define getters and setters on an object:
//
//Object.defineProperty(hello, "place", {
// set: (x) => {
// this.oldPlace = this.place;
// this.place = x;
// },
// get: (x) => {
// console.log(
// "Current place: " + this.place + "\nPlace before this: " + this.oldPlace
// );
// return this.place;
// },
//});
function getProxyObj(classes) {}
function init(obj: Object) {
obj.demon.css = {
classes: {
get: (className) => {}
}
};
}
export default {
init
};

@ -1,9 +1,8 @@
// @flow // @flow
import { get, set } from "idb-keyval"; import { get, set } from "idb-keyval";
import logger from "./utils/logger.js"; import logger from "./utils/logger.js";
import settingsInj from "./settings/settingsInj.js"; import settingsInj from "./settingsInj.js";
window.demonPlugins = {} //TODO: jank
const pluginsSym = Symbol("__plugins"); const pluginsSym = Symbol("__plugins");
async function init(obj: Object): Promise<boolean> { async function init(obj: Object): Promise<boolean> {
@ -23,15 +22,13 @@ async function init(obj: Object): Promise<boolean> {
return true; return true;
} }
async function addPlugin(iife: string): Promise<boolean> { async function addPlugin(iife: string, metadata: Object): Promise<boolean> {
// expected metadata: {name: "name", desc: "description", author: "author"} // expected metadata: {name: "name", desc: "description", author: "author"}
const exports: Object = (0, eval)(iife);
const metadata: Object = exports.metadata;
const obj: Object = { const obj: Object = {
// whether the plugin is started or stopped isn't going to be stored in the iDB, so it can be accessed more easily by all components // whether the plugin is started or stopped isn't going to be stored in the iDB, so it can be accessed more easily by all components
metadata: metadata, metadata: metadata,
iife: iife, iife: iife,
enabled: false // should plugins be enabled by default? not sure enabled: false, // should plugins be enabled by default? not sure
}; };
const globalSettings: Object = await get("demoncord"); const globalSettings: Object = await get("demoncord");
/*try { /*try {
@ -70,9 +67,6 @@ async function startPlugin(name: string): Promise<boolean> {
const exports: Object = (0, eval)(plug.iife); const exports: Object = (0, eval)(plug.iife);
const onStart: (ctx: Object) => void = exports.onStart; const onStart: (ctx: Object) => void = exports.onStart;
let ctx = {}; // ctx is how you're going to store things that need to be accessed in both onStart and onStop. dumb, i know let ctx = {}; // ctx is how you're going to store things that need to be accessed in both onStart and onStop. dumb, i know
if (plug.metadata.cumcord) {
ctx.cumcord = window.demon; //TODO: explicit cumcord compat layer.
}
onStart(ctx); onStart(ctx);
if (exports.settings) if (exports.settings)
settingsInj.registerSettingsEntry( settingsInj.registerSettingsEntry(
@ -81,7 +75,7 @@ async function startPlugin(name: string): Promise<boolean> {
exports.settings exports.settings
); );
logger.log(`Started ${name}!`, ["Plugins"]); logger.log(`Started ${name}!`, ["Plugins"]);
window.demonPlugins[pluginsSym][name] = { status: 1, ctx: ctx }; window.demon[pluginsSym][name] = { status: 1, ctx: ctx };
return true; return true;
} }
} }
@ -90,7 +84,7 @@ async function stopPlugin(name: string): Promise<boolean> {
const globalSettings = await get("demoncord"); const globalSettings = await get("demoncord");
if (globalSettings["plugin"][name] === undefined) { if (globalSettings["plugin"][name] === undefined) {
logger.error("Cannot stop non-existant or non-running plugin!", [ logger.error("Cannot stop non-existant or non-running plugin!", [
"Plugins" "Plugins",
]); ]);
return false; return false;
} else { } else {
@ -98,7 +92,7 @@ async function stopPlugin(name: string): Promise<boolean> {
const plug = globalSettings["plugin"][name]; const plug = globalSettings["plugin"][name];
const exports: Object = (0, eval)(plug.iife); const exports: Object = (0, eval)(plug.iife);
const onStop: (ctx: Object) => void = exports.onStop; const onStop: (ctx: Object) => void = exports.onStop;
onStop(window.demonPlugins[pluginsSym][name].ctx); onStop(window.demon[pluginsSym][name].ctx);
settingsInj.unregisterSettingsEntry("DEMON_PLUGIN_SETTINGS_" + name); settingsInj.unregisterSettingsEntry("DEMON_PLUGIN_SETTINGS_" + name);
logger.log(`Stopped ${name}!`, ["Plugins"]); logger.log(`Stopped ${name}!`, ["Plugins"]);
return true; return true;
@ -124,5 +118,5 @@ export default {
delPlugin, delPlugin,
startPlugin, startPlugin,
stopPlugin, stopPlugin,
togglePlugin togglePlugin,
}; };

@ -1,83 +0,0 @@
// @flow
/*import { make, join } from '@modules/styles';
import SettingsAPI from '@modules/apis/Settings';
import Manager, { modules } from '@modules/manager';
const styles = make('pluginCard');
const Settings = SettingsAPI.create('modules');
const { Filters } = Webpack;
const [
SwitchItem,
{ Heading },
SettingsIcon,
] = Webpack.bulk(
Filters.byDisplayName('SwitchItem'),
Filters.byProps('Heading'),
Filters.byDisplayName('Gear'),
);*/
import common from "../../../common";
import webpack from "../../../webpack";
const React = common.React;
const SwitchItem = webpack.findByDisplayName("SwitchItem");
const { Heading } = webpack.findByProps("Heading");
const SettingsIcon = webpack.findByDisplayName("Gear");
function useDidUpdateEffect(effect, deps?) {
const didMountRef = React.useRef(false);
React.useEffect(() => {
if (didMountRef.current) return effect();
// else set didMount to true
didMountRef.current = true;
}, deps);
}
export default (module: {
file: string,
name: string,
version: string,
description: string,
setPage: React.Dispatch<React.SetStateAction<string>>
}) => {
return (
<div className={styles.container}>
<div className={styles.headerContainer}>
<div className={styles.textContainer}>
<Heading
level={2}
lineClamp={1}
className={styles.text}
variant="heading-lg/medium"
>
{module.name}
</Heading>
<div className={styles.version}>{module.version}</div>
</div>
<SwitchItem
hideBorder
value={enabled}
onChange={setEnabled}
className={styles.switch}
/>
<div
className={join(
styles.settings,
!enabled || !settings ? styles.settingsDisabled : false
)}
>
<SettingsIcon
onClick={() =>
enabled && settings && setPage(module.file)
}
/>
</div>
</div>
<div className={styles.description}>{module.description}</div>
</div>
);
};

@ -1,16 +0,0 @@
// @flow
import webpack from "../../webpack.js";
import common from "../../common.js";
const React = common.React;
const FormTitle = webpack.findByDisplayName("FormTitle");
const FormDivider = webpack.findByDisplayName("FormDivider");
const FormSection = webpack.findByDisplayName("FormSection");
export default function (): any {
return (
<FormSection>
<FormTitle tag="h1">Demoncord Settings</FormTitle>
</FormSection>
);
}

@ -1,17 +0,0 @@
// @flow
import tmp from "./settingsInj.js";
const registerSettingsEntry = tmp.registerSettingsEntry;
import common from "../common.js";
const React = common.React;
import Settings from "./components/settings.jsx";
function init() {
console.log(Settings);
console.log(Settings());
registerSettingsEntry("General Settings", undefined, Settings);
}
export default {
init
};

@ -1,45 +1,38 @@
// @flow // @flow
import webpack from "../webpack.js"; import webpack from "./webpack";
import common from "../common.js";
const React = common.React;
const settingsSym = Symbol("__settings"); const settingsSym = Symbol("__settings");
window.demonSettings = {};
// super secret value that shouldnt be exposed, used internally to avoid section conflicts and the like // super secret value that shouldnt be exposed, used internally to avoid section conflicts and the like
const ovrwrtSctnSym: symbol = Symbol("__overwriteSection"); const ovrwrtSctnSym: symbol = Symbol("__overwriteSection");
const settingsView = webpack.findByDisplayName("SettingsView"); const settingsView = webpack.find(
(m) => m.default && m.default.displayName === "SettingsView"
);
type getPredicateSectionsEntry = type getPredicateSectionsEntry =
| { | {
section: "HEADER", section: "HEADER",
label: string label: string,
} }
| { | {
section: "DIVIDER" section: "DIVIDER",
} }
| { | {
section: string, section: string,
label: string, label: string,
component: Function component: Function,
}; };
function patch(args: mixed, ret: getPredicateSectionsEntry[]) { function patch(args: mixed, ret: getPredicateSectionsEntry[]) {
const processedEntries = window.demonSettings[settingsSym].entries.map( const processedEntries = window.demon[settingsSym].entries.map((e) => ({
(e) => ({ section:
section: (e[ovrwrtSctnSym] ?? "DEMON_SETTINGS_LOADER_") + e.name, (e[ovrwrtSctnSym] ? e[ovrwrtSctnSym] : "DEMON_SETTINGS_LOADER_") +
label: e.name, e.name,
element: e.component label: e.name,
}) element: e.component,
); }));
processedEntries.map((e) => {
console.log(e);
});
const injectionIndex = const injectionIndex =
2 + ret.findIndex((section) => section.section === "Game Activity"); 2 + ret.findIndex((section) => section.section === "Game Activity");
@ -54,28 +47,29 @@ function patch(args: mixed, ret: getPredicateSectionsEntry[]) {
} }
function init() { function init() {
const patcher = window.demon.require("patcher"); window.demon[settingsSym] = {
window.demonSettings[settingsSym] = { patch: window.demon.patcher.after(
patch: patcher.after(
"getPredicateSections", "getPredicateSections",
settingsView.default.prototype, settingsView.default.prototype,
patch patch
), ),
entries: [] entries: [],
}; };
// debug // debug
//window.__demontemp__UnpatchSettingsInj = unInit(); window.__demontemp__UnpatchSettingsInj = unInit();
} }
function unInit() { function unInit() {
window.demonSettings[settingsSym].patch(); window.demon[settingsSym].patch();
delete window.demonSettings[settingsSym]; delete window.demon[settingsSym];
} }
function unregisterSettingsEntry(name: string) { function unregisterSettingsEntry(name: string) {
let s = window.demonSettings[settingsSym]; let s = window.demon[settingsSym];
s.entries = s.entries.filter((e) => (e[ovrwrtSctnSym] ?? e.name) !== name); s.entries = s.entries.filter(
(e) => (e[ovrwrtSctnSym] ? e[ovrwrtSctnSym] : e.name) !== name
);
} }
function registerSettingsEntry( function registerSettingsEntry(
@ -85,9 +79,7 @@ function registerSettingsEntry(
): () => void { ): () => void {
let entry: { [symbol | string]: any } = { name, component }; let entry: { [symbol | string]: any } = { name, component };
if (section) entry[ovrwrtSctnSym] = section; if (section) entry[ovrwrtSctnSym] = section;
//entry.component.type = entry.component.type.default window.demon[settingsSym].entries.push(entry);
console.log(entry);
window.demonSettings[settingsSym].entries.push(entry);
return () => unregisterSettingsEntry(name); return () => unregisterSettingsEntry(name);
} }
@ -96,5 +88,5 @@ export default {
unInit, unInit,
registerSettingsEntry, registerSettingsEntry,
unregisterSettingsEntry, unregisterSettingsEntry,
ovrwrtSctnSymm: ovrwrtSctnSym ovrwrtSctnSymm: ovrwrtSctnSym,
}; };

@ -79,5 +79,5 @@ export default {
warn, warn,
error, error,
trace, trace,
group group,
}; };

@ -1,69 +1,60 @@
// @flow // @flow
type ModuleType = Object /* { [symbol]: any } */; type ModuleType = Object/* { [symbol]: any } */;
type FilterFunc = (module: ModuleType) => boolean; type FilterFunc = (module: ModuleType) => boolean;
function getModules(): any { function getModules(): any {
let modules: { c: mixed[] } = {}; let modules: { c: mixed[] } = {};
window.webpackChunkdiscord_app.push([ window.webpackChunkdiscord_app.push([
[Math.random().toString(36)], [Math.random().toString(36)],
{}, {},
(e) => { (e) => {
modules = e; modules = e;
} },
]); ]);
return modules.c; return modules.c;
} }
function filter(filter: FilterFunc, moduleList: any): Array<Object> { function filter(filter: FilterFunc, moduleList: any): Array<Object> {
let modules: Array<mixed[]> = []; let modules: Array<mixed[]> = [];
for (const mod in moduleList) { for (const mod in moduleList) {
const module = moduleList[mod].exports; const module = moduleList[mod].exports;
if (module) { if (module) {
if (module.default && module.__esModule && filter(module.default)) { if (module.default && module.__esModule && filter(module.default)) {
modules.push(module.default); modules.push(module.default);
} else if (filter(module)) { } else if (filter(module)) {
modules.push(module); modules.push(module);
} }
}
} }
return modules; }
return modules;
} }
type WebpackModules = { type WebpackModules = {
modules: () => any, modules: () => any,
filter: (filter: FilterFunc, moduleList: any) => Object[], filter: (filter: FilterFunc, moduleList: any) => Object[],
find: (filter: FilterFunc) => Object, find: (filter: FilterFunc) => Object,
findAll: (filter: FilterFunc) => Object[], findAll: (filter: FilterFunc) => Object[],
findByProps: (...props: string[]) => Object, findByProps: (...props: string[]) => Object,
findByPropsAll: (...props: string[]) => Object[], findByPropsAll: (...props: string[]) => Object[],
findByDisplayName: (prop: string) => Object[],
reloadModules: () => void
}; };
let webpack: WebpackModules = { let webpack: WebpackModules = {
modules: getModules(), modules: getModules(),
filter: filter, filter: filter,
find: (filter: FilterFunc) => webpack.filter(filter, webpack.modules)[0], find: (filter: FilterFunc) => webpack.filter(filter, webpack.modules)[0],
findAll: (filter: FilterFunc) => webpack.filter(filter, webpack.modules), findAll: (filter: FilterFunc) => webpack.filter(filter, webpack.modules),
findByProps: (...props: Array<string>) => { findByProps: (...props: Array<string>) => {
return webpack.find((module) => { return webpack.find((module) => {
return props.every((prop) => module[prop] !== undefined); return props.every((prop) => module[prop] !== undefined);
}); });
}, },
findByPropsAll: (...props: Array<string>) => { findByPropsAll: (...props: Array<string>) => {
return webpack.findAll((module) => return webpack.findAll((module) =>
props.every((prop) => module[prop] !== undefined) props.every((prop) => module[prop] !== undefined)
); );
}, },
findByDisplayName: (prop: string) => {
return webpack.find((m) => m?.default?.displayName === prop);
},
reloadModules: () => {
//NOTE: i have no idea why this could even feasibly need to be used, but i'm adding it anyways
webpack.modules = getModules();
}
}; };
export default webpack; export default webpack;

@ -1,34 +1,7 @@
// @flow import init from "./init.js"
import init from "./init.js";
import settingsInj from "./api/settings/settingsInj";
import commands from "./api/commands";
const obj = {}; if (window.demon) {
delete window.demon; // this is a very good idea
init(obj);
window.demon = {};
function isAllowed(mod: String): boolean {
//TODO: permissions checking
return true;
} }
window.demon.require = (mod: String): Object => { init(window)
if (!isAllowed(mod)) {
throw new Error("Not allowed!"); //TODO: make this not irrepairably error out
}
const mods = mod.split("/");
let res = obj.demon;
mods.forEach((m) => {
if (m in res) {
res = res[m];
} else {
throw new Error("Module does not exist!");
}
});
return res;
};
settingsInj.init();
commands.init(obj);

@ -2,10 +2,9 @@
import Patcher from "simian"; import Patcher from "simian";
import webpack from "./api/webpack"; import webpack from "./api/webpack";
import common from "./api/common"; import common from "./api/common";
import plugins from "./api/plugins";
import settings from "./api/settings/settings";
import css from "./api/css";
import commands from "./api/commands"; import commands from "./api/commands";
import plugins from "./api/plugins";
import settingsInj from "./api/settingsInj";
async function init(obj: Object): Promise<void> { async function init(obj: Object): Promise<void> {
const patcher = new Patcher(); const patcher = new Patcher();
@ -31,17 +30,20 @@ async function init(obj: Object): Promise<void> {
}, },
before: patcher.before, before: patcher.before,
instead: patcher.instead, instead: patcher.instead,
after: patcher.after after: patcher.after,
}, },
webpack, webpack,
common, common,
commands: { commands: {
add: commands.add add: commands.add,
}, },
plugins __DO_NOT_USE_OR_YOU_WILL_BE_FIRED_UNTO_THE_DEPTHS_OF_HELL: {
plugins,
}
}; };
commands.init(obj);
settingsInj.init();
plugins.init(obj); plugins.init(obj);
css.init(obj);
} }
export default init; export default init;

Loading…
Cancel
Save