First pass polyfill

This commit is contained in:
Zack Rauen 2022-09-05 23:58:16 -04:00
parent ff8280e2b5
commit 3b9ad9b75b
25 changed files with 893 additions and 223 deletions

View File

@ -1,7 +1,8 @@
{
"extends": "eslint:recommended",
"env": {
"node": true
"node": true,
"es2020": true
},
"parserOptions": {
"ecmaVersion": 2022,
@ -82,15 +83,7 @@
"yoda": "error"
},
"globals": {
"Proxy": "readonly",
"Set": "readonly",
"WeakMap": "readonly",
"WeakSet": "readonly",
"Map": "readonly",
"Promise": "readonly",
"Reflect": "readonly",
"DiscordNative": "readonly",
"__non_webpack_require__": "readonly",
"Symbol": "readonly"
"__non_webpack_require__": "readonly"
}
}

19
common/clone.js Normal file
View File

@ -0,0 +1,19 @@
export function getKeys(object) {
const keys = [];
for (const key in object) keys.push(key);
return keys;
}
export default function cloneObject(target, newObject = {}, keys) {
if (!Array.isArray(keys)) keys = getKeys(target);
return keys.reduce((clone, key) => {
if (typeof(target[key]) === "object" && !Array.isArray(target[key]) && target[key] !== null) clone[key] = cloneObject(target[key], {});
else if (typeof target[key] === "function") clone[key] = target[key].bind(target);
else clone[key] = target[key];
return clone;
}, newObject);
}

36
common/events.js Normal file
View File

@ -0,0 +1,36 @@
import Logger from "./logger";
export default class EventEmitter {
static get EventEmitter() {return EventEmitter;}
constructor() {
this.events = {};
}
setMaxListeners() {}
on(event, callback) {
if (!this.events[event]) this.events[event] = new Set();
this.events[event].add(callback);
}
emit(event, ...args) {
if (!this.events[event]) return;
for (const [index, listener] of this.events[event].entries()) {
try {
listener(...args);
}
catch (error) {
Logger.error("Emitter", `Cannot fire listener for event ${event} at position ${index}:`, error);
}
}
}
off(event, callback) {
if (!this.events[event]) return;
return this.events[event].delete(callback);
}
}

View File

@ -65,7 +65,8 @@ export default class BetterDiscord {
try {
${content}
return true;
} catch {
} catch(error) {
console.error(error);
return false;
}
})();

View File

@ -11,17 +11,17 @@
"build-preload": "pnpm --filter preload build",
"pack-emotes": "node scripts/emotes.js",
"inject": "node scripts/inject.js",
"lint": "eslint --ext .js common/ && pnpm --filter injector lint && pnpm --filter preload lint && pnpm --filter renderer lint",
"lint": "eslint --ext .js common/ && pnpm --filter injector lint && pnpm --filter preload lint && pnpm --filter renderer lint-js",
"test": "mocha --require @babel/register --recursive \"./tests/renderer/*.js\"",
"dist": "pnpm run build-prod && node scripts/pack.js",
"api": "jsdoc -X renderer/src/modules/pluginapi.js > jsdoc-ast.json"
},
"devDependencies": {
"asar": "^3.0.3",
"eslint": "^7.12.0",
"eslint-plugin-react": "^7.21.5",
"asar": "^3.2.0",
"eslint": "^8.23.0",
"eslint-plugin-react": "^7.31.6",
"mocha": "^10.0.0",
"webpack": "^5.73.0",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0"
},
"engines": {

View File

@ -4,19 +4,19 @@ importers:
.:
specifiers:
asar: ^3.0.3
eslint: ^7.12.0
eslint-plugin-react: ^7.21.5
asar: ^3.2.0
eslint: ^8.23.0
eslint-plugin-react: ^7.31.6
mocha: ^10.0.0
webpack: ^5.73.0
webpack: ^5.74.0
webpack-cli: ^4.10.0
devDependencies:
asar: 3.1.0
eslint: 7.32.0
eslint-plugin-react: 7.30.1_eslint@7.32.0
asar: 3.2.0
eslint: 8.23.0
eslint-plugin-react: 7.31.6_eslint@8.23.0
mocha: 10.0.0
webpack: 5.73.0_webpack-cli@4.10.0
webpack-cli: 4.10.0_webpack@5.73.0
webpack: 5.74.0_webpack-cli@4.10.0
webpack-cli: 4.10.0_webpack@5.74.0
injector:
specifiers:
@ -76,12 +76,6 @@ packages:
'@jridgewell/trace-mapping': 0.3.14
dev: true
/@babel/code-frame/7.12.11:
resolution: {integrity: sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==}
dependencies:
'@babel/highlight': 7.17.12
dev: true
/@babel/code-frame/7.18.6:
resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==}
engines: {node: '>=6.9.0'}
@ -150,7 +144,7 @@ packages:
'@babel/compat-data': 7.18.8
'@babel/core': 7.18.6
'@babel/helper-validator-option': 7.18.6
browserslist: 4.21.0
browserslist: 4.21.1
semver: 6.3.0
dev: true
@ -319,11 +313,6 @@ packages:
'@babel/types': 7.18.8
dev: true
/@babel/helper-validator-identifier/7.16.7:
resolution: {integrity: sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==}
engines: {node: '>=6.9.0'}
dev: true
/@babel/helper-validator-identifier/7.18.6:
resolution: {integrity: sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==}
engines: {node: '>=6.9.0'}
@ -357,15 +346,6 @@ packages:
- supports-color
dev: true
/@babel/highlight/7.17.12:
resolution: {integrity: sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/helper-validator-identifier': 7.16.7
chalk: 2.4.2
js-tokens: 4.0.0
dev: true
/@babel/highlight/7.18.6:
resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==}
engines: {node: '>=6.9.0'}
@ -1331,25 +1311,25 @@ packages:
engines: {node: '>=10.0.0'}
dev: true
/@eslint/eslintrc/0.4.3:
resolution: {integrity: sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==}
engines: {node: ^10.12.0 || >=12.0.0}
/@eslint/eslintrc/1.3.1:
resolution: {integrity: sha512-OhSY22oQQdw3zgPOOwdoj01l/Dzl1Z+xyUP33tkSN+aqyEhymJCcPHyXt+ylW8FSe0TfRC2VG+ROQOapD0aZSQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
ajv: 6.12.6
debug: 4.3.4
espree: 7.3.1
espree: 9.4.0
globals: 13.15.0
ignore: 4.0.6
ignore: 5.2.0
import-fresh: 3.3.0
js-yaml: 3.14.1
js-yaml: 4.1.0
minimatch: 3.1.2
strip-json-comments: 3.1.1
transitivePeerDependencies:
- supports-color
dev: true
/@humanwhocodes/config-array/0.5.0:
resolution: {integrity: sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==}
/@humanwhocodes/config-array/0.10.4:
resolution: {integrity: sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==}
engines: {node: '>=10.10.0'}
dependencies:
'@humanwhocodes/object-schema': 1.2.1
@ -1359,6 +1339,15 @@ packages:
- supports-color
dev: true
/@humanwhocodes/gitignore-to-minimatch/1.0.2:
resolution: {integrity: sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==}
dev: true
/@humanwhocodes/module-importer/1.0.1:
resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
engines: {node: '>=12.22'}
dev: true
/@humanwhocodes/object-schema/1.2.1:
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
dev: true
@ -1591,14 +1580,14 @@ packages:
'@xtuc/long': 4.2.2
dev: true
/@webpack-cli/configtest/1.2.0_77l47gmqkrqiei5z7sbwz5iaj4:
/@webpack-cli/configtest/1.2.0_5v66e2inugklgvlh4huuavolfq:
resolution: {integrity: sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==}
peerDependencies:
webpack: 4.x.x || 5.x.x
webpack-cli: 4.x.x
dependencies:
webpack: 5.73.0_webpack-cli@4.10.0
webpack-cli: 4.10.0_webpack@5.73.0
webpack: 5.74.0_webpack-cli@4.10.0
webpack-cli: 4.10.0_webpack@5.74.0
dev: true
/@webpack-cli/info/1.5.0_webpack-cli@4.10.0:
@ -1607,7 +1596,7 @@ packages:
webpack-cli: 4.x.x
dependencies:
envinfo: 7.8.1
webpack-cli: 4.10.0_webpack@5.73.0
webpack-cli: 4.10.0_webpack@5.74.0
dev: true
/@webpack-cli/serve/1.7.0_webpack-cli@4.10.0:
@ -1619,7 +1608,7 @@ packages:
webpack-dev-server:
optional: true
dependencies:
webpack-cli: 4.10.0_webpack@5.73.0
webpack-cli: 4.10.0_webpack@5.74.0
dev: true
/@xtuc/ieee754/1.2.0:
@ -1638,18 +1627,12 @@ packages:
acorn: 8.7.1
dev: true
/acorn-jsx/5.3.2_acorn@7.4.1:
/acorn-jsx/5.3.2_acorn@8.8.0:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies:
acorn: 7.4.1
dev: true
/acorn/7.4.1:
resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==}
engines: {node: '>=0.4.0'}
hasBin: true
acorn: 8.8.0
dev: true
/acorn/8.7.1:
@ -1658,6 +1641,12 @@ packages:
hasBin: true
dev: true
/acorn/8.8.0:
resolution: {integrity: sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==}
engines: {node: '>=0.4.0'}
hasBin: true
dev: true
/ajv-keywords/3.5.2_ajv@6.12.6:
resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==}
peerDependencies:
@ -1689,11 +1678,6 @@ packages:
engines: {node: '>=6'}
dev: true
/ansi-colors/4.1.3:
resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
engines: {node: '>=6'}
dev: true
/ansi-regex/5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
@ -1721,12 +1705,6 @@ packages:
picomatch: 2.3.1
dev: true
/argparse/1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
dependencies:
sprintf-js: 1.0.3
dev: true
/argparse/2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
dev: true
@ -1779,8 +1757,8 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/asar/3.1.0:
resolution: {integrity: sha512-vyxPxP5arcAqN4F/ebHd/HhwnAiZtwhglvdmc7BR2f0ywbVNTOpSeyhLDbGXtE/y58hv1oC75TaNIXutnsOZsQ==}
/asar/3.2.0:
resolution: {integrity: sha512-COdw2ZQvKdFGFxXwX3oYh2/sOsJWJegrdJCGxnN4MZ7IULgRBp9P6665aqj9z1v9VwP4oP1hRBojRDQ//IGgAg==}
engines: {node: '>=10.12.0'}
hasBin: true
dependencies:
@ -1912,7 +1890,7 @@ packages:
hasBin: true
dependencies:
caniuse-lite: 1.0.30001359
electron-to-chromium: 1.4.170
electron-to-chromium: 1.4.185
node-releases: 2.0.5
update-browserslist-db: 1.0.4_browserslist@4.21.0
dev: true
@ -2055,7 +2033,7 @@ packages:
dev: true
/color-name/1.1.3:
resolution: {integrity: sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=}
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
dev: true
/color-name/1.1.4:
@ -2089,7 +2067,7 @@ packages:
dev: true
/concat-map/0.0.1:
resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
dev: true
/convert-source-map/1.8.0:
@ -2254,10 +2232,6 @@ packages:
esutils: 2.0.3
dev: true
/electron-to-chromium/1.4.170:
resolution: {integrity: sha512-rZ8PZLhK4ORPjFqLp9aqC4/S1j4qWFsPPz13xmWdrbBkU/LlxMcok+f+6f8YnQ57MiZwKtOaW15biZZsY5Igvw==}
dev: true
/electron-to-chromium/1.4.185:
resolution: {integrity: sha512-9kV/isoOGpKkBt04yYNaSWIBn3187Q5VZRtoReq8oz5NY/A4XmU6cAoqgQlDp7kKJCZMRjWZ8nsQyxfpFHvfyw==}
dev: true
@ -2271,19 +2245,20 @@ packages:
engines: {node: '>= 4'}
dev: true
/enhanced-resolve/5.9.3:
resolution: {integrity: sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==}
/enhanced-resolve/5.10.0:
resolution: {integrity: sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==}
engines: {node: '>=10.13.0'}
dependencies:
graceful-fs: 4.2.10
tapable: 2.2.1
dev: true
/enquirer/2.3.6:
resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==}
engines: {node: '>=8.6'}
/enhanced-resolve/5.9.3:
resolution: {integrity: sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==}
engines: {node: '>=10.13.0'}
dependencies:
ansi-colors: 4.1.3
graceful-fs: 4.2.10
tapable: 2.2.1
dev: true
/envinfo/7.8.1:
@ -2361,8 +2336,8 @@ packages:
engines: {node: '>=10'}
dev: true
/eslint-plugin-react/7.30.1_eslint@7.32.0:
resolution: {integrity: sha512-NbEvI9jtqO46yJA3wcRF9Mo0lF9T/jhdHqhCHXiXtD+Zcb98812wvokjWpU7Q4QH5edo6dmqrukxVvWWXHlsUg==}
/eslint-plugin-react/7.31.6_eslint@8.23.0:
resolution: {integrity: sha512-CXu4eu28sb8Sd2+cyUYsJVyDvpTlaXPG+bOzzpS9IzZKtye96AYX3ZmHQ6ayn/OAIQ/ufDJP8ElPWd63Pepn9w==}
engines: {node: '>=4'}
peerDependencies:
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
@ -2370,7 +2345,7 @@ packages:
array-includes: 3.1.5
array.prototype.flatmap: 1.3.0
doctrine: 2.1.0
eslint: 7.32.0
eslint: 8.23.0
estraverse: 5.3.0
jsx-ast-utils: 3.3.1
minimatch: 3.1.2
@ -2392,16 +2367,22 @@ packages:
estraverse: 4.3.0
dev: true
/eslint-utils/2.1.0:
resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==}
engines: {node: '>=6'}
/eslint-scope/7.1.1:
resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
eslint-visitor-keys: 1.3.0
esrecurse: 4.3.0
estraverse: 5.3.0
dev: true
/eslint-visitor-keys/1.3.0:
resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==}
engines: {node: '>=4'}
/eslint-utils/3.0.0_eslint@8.23.0:
resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==}
engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0}
peerDependencies:
eslint: '>=5'
dependencies:
eslint: 8.23.0
eslint-visitor-keys: 2.1.0
dev: true
/eslint-visitor-keys/2.1.0:
@ -2409,68 +2390,66 @@ packages:
engines: {node: '>=10'}
dev: true
/eslint/7.32.0:
resolution: {integrity: sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==}
engines: {node: ^10.12.0 || >=12.0.0}
/eslint-visitor-keys/3.3.0:
resolution: {integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
/eslint/8.23.0:
resolution: {integrity: sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
hasBin: true
dependencies:
'@babel/code-frame': 7.12.11
'@eslint/eslintrc': 0.4.3
'@humanwhocodes/config-array': 0.5.0
'@eslint/eslintrc': 1.3.1
'@humanwhocodes/config-array': 0.10.4
'@humanwhocodes/gitignore-to-minimatch': 1.0.2
'@humanwhocodes/module-importer': 1.0.1
ajv: 6.12.6
chalk: 4.1.2
cross-spawn: 7.0.3
debug: 4.3.4
doctrine: 3.0.0
enquirer: 2.3.6
escape-string-regexp: 4.0.0
eslint-scope: 5.1.1
eslint-utils: 2.1.0
eslint-visitor-keys: 2.1.0
espree: 7.3.1
eslint-scope: 7.1.1
eslint-utils: 3.0.0_eslint@8.23.0
eslint-visitor-keys: 3.3.0
espree: 9.4.0
esquery: 1.4.0
esutils: 2.0.3
fast-deep-equal: 3.1.3
file-entry-cache: 6.0.1
find-up: 5.0.0
functional-red-black-tree: 1.0.1
glob-parent: 5.1.2
glob-parent: 6.0.2
globals: 13.15.0
ignore: 4.0.6
globby: 11.1.0
grapheme-splitter: 1.0.4
ignore: 5.2.0
import-fresh: 3.3.0
imurmurhash: 0.1.4
is-glob: 4.0.3
js-yaml: 3.14.1
js-yaml: 4.1.0
json-stable-stringify-without-jsonify: 1.0.1
levn: 0.4.1
lodash.merge: 4.6.2
minimatch: 3.1.2
natural-compare: 1.4.0
optionator: 0.9.1
progress: 2.0.3
regexpp: 3.2.0
semver: 7.3.7
strip-ansi: 6.0.1
strip-json-comments: 3.1.1
table: 6.8.0
text-table: 0.2.0
v8-compile-cache: 2.3.0
transitivePeerDependencies:
- supports-color
dev: true
/espree/7.3.1:
resolution: {integrity: sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==}
engines: {node: ^10.12.0 || >=12.0.0}
/espree/9.4.0:
resolution: {integrity: sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
acorn: 7.4.1
acorn-jsx: 5.3.2_acorn@7.4.1
eslint-visitor-keys: 1.3.0
dev: true
/esprima/4.0.1:
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
engines: {node: '>=4'}
hasBin: true
acorn: 8.8.0
acorn-jsx: 5.3.2_acorn@8.8.0
eslint-visitor-keys: 3.3.0
dev: true
/esquery/1.4.0:
@ -2713,6 +2692,13 @@ packages:
is-glob: 4.0.3
dev: true
/glob-parent/6.0.2:
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
engines: {node: '>=10.13.0'}
dependencies:
is-glob: 4.0.3
dev: true
/glob-to-regexp/0.4.1:
resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
dev: true
@ -2810,6 +2796,10 @@ packages:
resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==}
dev: true
/grapheme-splitter/1.0.4:
resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==}
dev: true
/hard-rejection/2.1.0:
resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==}
engines: {node: '>=6'}
@ -2884,11 +2874,6 @@ packages:
postcss: 8.4.14
dev: true
/ignore/4.0.6:
resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==}
engines: {node: '>= 4'}
dev: true
/ignore/5.2.0:
resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==}
engines: {node: '>= 4'}
@ -3120,14 +3105,6 @@ packages:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
dev: true
/js-yaml/3.14.1:
resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
hasBin: true
dependencies:
argparse: 1.0.10
esprima: 4.0.1
dev: true
/js-yaml/4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
@ -3903,11 +3880,6 @@ packages:
engines: {node: '>= 0.8'}
dev: true
/progress/2.0.3:
resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
engines: {node: '>=0.4.0'}
dev: true
/prop-types/15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
dependencies:
@ -4256,10 +4228,6 @@ packages:
resolution: {integrity: sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==}
dev: true
/sprintf-js/1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
dev: true
/string-width/4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
@ -4462,7 +4430,31 @@ packages:
schema-utils: 3.1.1
serialize-javascript: 6.0.0
terser: 5.14.1
webpack: 5.73.0_webpack-cli@4.10.0
webpack: 5.73.0
dev: true
/terser-webpack-plugin/5.3.3_webpack@5.74.0:
resolution: {integrity: sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ==}
engines: {node: '>= 10.13.0'}
peerDependencies:
'@swc/core': '*'
esbuild: '*'
uglify-js: '*'
webpack: ^5.1.0
peerDependenciesMeta:
'@swc/core':
optional: true
esbuild:
optional: true
uglify-js:
optional: true
dependencies:
'@jridgewell/trace-mapping': 0.3.14
jest-worker: 27.5.1
schema-utils: 3.1.1
serialize-javascript: 6.0.0
terser: 5.14.1
webpack: 5.74.0_webpack-cli@4.10.0
dev: true
/terser/5.14.1:
@ -4471,7 +4463,7 @@ packages:
hasBin: true
dependencies:
'@jridgewell/source-map': 0.3.2
acorn: 8.7.1
acorn: 8.8.0
commander: 2.20.3
source-map-support: 0.5.21
dev: true
@ -4616,7 +4608,7 @@ packages:
graceful-fs: 4.2.10
dev: true
/webpack-cli/4.10.0_webpack@5.73.0:
/webpack-cli/4.10.0_webpack@5.74.0:
resolution: {integrity: sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==}
engines: {node: '>=10.13.0'}
hasBin: true
@ -4637,7 +4629,7 @@ packages:
optional: true
dependencies:
'@discoveryjs/json-ext': 0.5.7
'@webpack-cli/configtest': 1.2.0_77l47gmqkrqiei5z7sbwz5iaj4
'@webpack-cli/configtest': 1.2.0_5v66e2inugklgvlh4huuavolfq
'@webpack-cli/info': 1.5.0_webpack-cli@4.10.0
'@webpack-cli/serve': 1.7.0_webpack-cli@4.10.0
colorette: 2.0.19
@ -4647,7 +4639,7 @@ packages:
import-local: 3.1.0
interpret: 2.2.0
rechoir: 0.7.1
webpack: 5.73.0_webpack-cli@4.10.0
webpack: 5.74.0_webpack-cli@4.10.0
webpack-merge: 5.8.0
dev: true
@ -4704,8 +4696,8 @@ packages:
- uglify-js
dev: true
/webpack/5.73.0_webpack-cli@4.10.0:
resolution: {integrity: sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA==}
/webpack/5.74.0_webpack-cli@4.10.0:
resolution: {integrity: sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==}
engines: {node: '>=10.13.0'}
hasBin: true
peerDependencies:
@ -4721,9 +4713,9 @@ packages:
'@webassemblyjs/wasm-parser': 1.11.1
acorn: 8.7.1
acorn-import-assertions: 1.8.0_acorn@8.7.1
browserslist: 4.21.0
browserslist: 4.21.1
chrome-trace-event: 1.0.3
enhanced-resolve: 5.9.3
enhanced-resolve: 5.10.0
es-module-lexer: 0.9.3
eslint-scope: 5.1.1
events: 3.3.0
@ -4735,9 +4727,9 @@ packages:
neo-async: 2.6.2
schema-utils: 3.1.1
tapable: 2.2.1
terser-webpack-plugin: 5.3.3_webpack@5.73.0
terser-webpack-plugin: 5.3.3_webpack@5.74.0
watchpack: 2.4.0
webpack-cli: 4.10.0_webpack@5.73.0
webpack-cli: 4.10.0_webpack@5.74.0
webpack-sources: 3.2.3
transitivePeerDependencies:
- '@swc/core'

28
preload/src/api/crypto.js Normal file
View File

@ -0,0 +1,28 @@
const crypto = (() => {
let cache = null;
return () => {
if (cache) return cache;
return cache = __non_webpack_require__("crypto");
};
})();
export function createHash(type) {
const hash = crypto().createHash(type);
const ctx = {
update(data) {
hash.update(data);
return ctx;
},
digest(encoding) {return hash.digest(encoding);}
};
return ctx;
}
export function randomBytes(length) {
return crypto().randomBytes(length);
}

View File

@ -0,0 +1,13 @@
import {ipcRenderer as IPC, shell} from "electron";
export const ipcRenderer = {
send: IPC.send.bind(IPC),
sendToHost: IPC.sendToHost.bind(IPC),
sendTo: IPC.sendTo.bind(IPC),
sendSync: IPC.sendSync.bind(IPC),
invoke: IPC.invoke.bind(IPC),
on: IPC.on.bind(IPC),
off: IPC.off.bind(IPC)
};
export {shell};

View File

@ -0,0 +1,73 @@
import * as fs from "fs";
import cloneObject from "common/clone";
import Logger from "common/logger";
export function readFile(path, options = "utf8") {
return fs.readFileSync(path, options);
}
export function writeFile(path, content, options) {
if (content instanceof Uint8Array) {
content = Buffer.from(content);
}
const doWriteFile = options?.originalFs ? __non_webpack_require__("original-fs").writeFileSync : fs.writeFileSync;
return doWriteFile(path, content, options);
}
export function readDirectory(path, options) {
return fs.readdirSync(path, options);
}
export function createDirectory(path, options) {
return fs.mkdirSync(path, options);
}
export function deleteDirectory(path, options) {
fs.rmdirSync(path, options);
}
export function exists(path) {
return fs.existsSync(path);
}
export function getRealPath(path, options) {
return fs.realpathSync(path, options);
}
export function rename(oldPath, newPath) {
return fs.renameSync(oldPath, newPath);
}
export function createWriteStream(path, options) {
return cloneObject(fs.createWriteStream(path, options));
}
export function watch(path, options, callback) {
const watcher = fs.watch(path, options, (event, filename) => {
try {
callback(event, filename);
}
catch (error) {
Logger.stacktrace("filesystem", "Failed to watch path", error);
}
});
return {
close: () => {
watcher.close();
}
};
}
export function getStats(path, options) {
const stats = fs.statSync(path, options);
return {
...stats,
isFile: stats.isFile.bind(stats),
isDirectory: stats.isDirectory.bind(stats),
isSymbolicLink: stats.isSymbolicLink.bind(stats)
};
}

91
preload/src/api/https.js Normal file
View File

@ -0,0 +1,91 @@
import Logger from "common/logger";
let request;
const req = function (url, options, callback) {
if (!request) request = __non_webpack_require__("request");
return request(url, options, (error, res, body) => {
try {
Reflect.apply(callback, null, [error, res, body]);
}
catch (err) {
Logger.stacktrace("https", "Failed request", err);
}
});
};
export const get = function (url, options, callback) {
if (!request) request = __non_webpack_require__("request");
return request.get(url, options, (error, res, body) => {
try {
Reflect.apply(callback, null, [error, res, body]);
}
catch (err) {
Logger.stacktrace("https", "Failed get request", err);
}
});
};
export const put = function (url, options, callback) {
if (!request) request = __non_webpack_require__("request");
return request.put(url, options, (error, res, body) => {
try {
Reflect.apply(callback, null, [error, res, body]);
}
catch (err) {
Logger.stacktrace("https", "Failed put request", err);
}
});
};
export const post = function (url, options, callback) {
if (!request) request = __non_webpack_require__("request");
return request.post(url, options, (error, res, body) => {
try {
Reflect.apply(callback, null, [error, res, body]);
}
catch (err) {
Logger.stacktrace("https", "Failed post request", err);
}
});
};
const del = function (url, options, callback) {
if (!request) request = __non_webpack_require__("request");
return request.delete(url, options, (error, res, body) => {
try {
Reflect.apply(callback, null, [error, res, body]);
}
catch (err) {
Logger.stacktrace("https", "Failed delete request", err);
}
});
};
const head = function (url, options, callback) {
if (!request) request = __non_webpack_require__("request");
return request.head(url, options, (error, res, body) => {
try {
Reflect.apply(callback, null, [error, res, body]);
}
catch (err) {
Logger.stacktrace("https", "Failed head request", err);
}
});
};
export default req;
Object.assign(req, {
get,
put,
post,
head,
delete: del // eslint-disable-line quote-props
});

14
preload/src/api/index.js Normal file
View File

@ -0,0 +1,14 @@
import path from "path";
import Module from "module";
Module.globalPaths.push(path.resolve(process.env.DISCORD_APP_PATH, "..", "app.asar", "node_modules"));
export * as filesystem from "./filesystem";
export * as https from "./https";
export * as electron from "./electron";
export * as crypto from "./crypto";
// We can expose that without any issues.
export * as path from "path";
export * as net from "net"; // TODO: evaluate need and create wrapper
export * as os from "os";

View File

@ -1,59 +1,15 @@
const Module = require("module");
const path = require("path");
const electron = require("electron");
const NodeEvents = require("events");
import {contextBridge} from "electron";
import newProcess from "./process";
import * as BdApi from "./api";
import init from "./init";
const cloneObject = function (target, newObject = {}, keys) {
if (!Array.isArray(keys)) keys = Object.keys(Object.getOwnPropertyDescriptors(target));
return keys.reduce((clone, key) => {
if (typeof(target[key]) === "object" && !Array.isArray(target[key]) && target[key] !== null && !(target[key] instanceof NodeEvents)) clone[key] = cloneObject(target[key], {});
else clone[key] = target[key];
return clone;
}, newObject);
};
/* global window:false */
// const context = electron.webFrame.top.context;
Object.defineProperty(window, "webpackJsonp", {
get: () => electron.webFrame.top.context.webpackJsonp
let hasInitialized = false;
contextBridge.exposeInMainWorld("BetterDiscord", BdApi);
contextBridge.exposeInMainWorld("process", newProcess);
contextBridge.exposeInMainWorld("BetterDiscordPreload", () => {
if (hasInitialized) return null;
hasInitialized = true;
return BdApi;
});
electron.webFrame.top.context.global = electron.webFrame.top.context;
electron.webFrame.top.context.require = require;
electron.webFrame.top.context.Buffer = Buffer;
electron.webFrame.top.context.process = new class PatchedProcess extends NodeEvents {
get __ORIGINAL_PROCESS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED__() {return process;}
constructor() {
super();
Object.assign(this,
cloneObject(process, {}, Object.keys(NodeEvents.prototype)),
cloneObject(process, {})
);
}
};
// Load Discord's original preload
const preload = process.env.DISCORD_PRELOAD;
if (preload) {
// Restore original preload for future windows
electron.ipcRenderer.send("bd-register-preload", preload);
// Run original preload
try {
const originalKill = process.kill;
process.kill = function() {};
require(preload);
process.kill = originalKill;
}
catch (e) {
// TODO bail out
}
}
Module.globalPaths.push(path.resolve(process.env.DISCORD_APP_PATH, "..", "app.asar", "node_modules"));
init();

22
preload/src/init.js Normal file
View File

@ -0,0 +1,22 @@
import {ipcRenderer as IPC} from "electron";
import * as IPCEvents from "common/constants/ipcevents";
export default function() {
// Load Discord's original preload
const preload = process.env.DISCORD_PRELOAD;
if (preload) {
// Restore original preload for future windows
IPC.send(IPCEvents.REGISTER_PRELOAD, preload);
// Run original preload
try {
const originalKill = process.kill;
process.kill = function() {};
__non_webpack_require__(preload);
process.kill = originalKill;
}
catch (e) {
// TODO bail out
}
}
}

3
preload/src/process.js Normal file
View File

@ -0,0 +1,3 @@
import cloneObject from "common/clone";
export default cloneObject(process, {});

View File

@ -19,7 +19,9 @@ module.exports = (env, argv) => ({
rimraf: `require("rimraf")`,
yauzl: `require("yauzl")`,
mkdirp: `require("mkdirp")`,
module: `require("module")`
module: `require("module")`,
os: `require("os")`,
net: `require("net")`
},
resolve: {
extensions: [".js"],

View File

@ -1,3 +1,4 @@
import require from "./polyfill"; // eslint-disable-line no-unused-vars
import secure from "./secure";
import patchModuleLoad from "./moduleloader";
import LoadingIcon from "./loadingicon";
@ -8,6 +9,7 @@ import BdApi from "./modules/pluginapi";
secure();
patchModuleLoad();
window.BdApi = BdApi;
window.global = window;
// Add loading icon at the bottom right
LoadingIcon.show();

View File

@ -0,0 +1,17 @@
import WebpackModules from "../modules/webpackmodules";
Object.defineProperty(window, "Buffer", {
get() {return Buffer.getBuffer().Buffer;},
configurable: true,
enumerable: false
});
export default class Buffer {
static getBuffer() {
if (this.cached) return this.cached;
this.cached = WebpackModules.getByProps("Buffer", "SlowBuffer");
return this.cached;
}
}

View File

@ -0,0 +1,9 @@
import Remote from "./remote";
export default {
...Remote.crypto,
// Wrap it in Buffer
randomBytes(length) {
return Buffer.from(Remote.crypto.randomBytes(length));
}
};

167
renderer/src/polyfill/fs.js Normal file
View File

@ -0,0 +1,167 @@
import Remote from "./remote";
export const readFileSync = function (path, options = "utf8") {
return Remote.filesystem.readFile(path, options);
};
export const readFile = function (path, options = "utf8", callback) {
try {
const contents = Remote.filesystem.readFile(path, options);
callback(null, contents);
}
catch (error) {
callback(error, null);
}
};
export const writeFile = function (path, data, options = "utf8", callback) {
if (typeof(options) === "function") {
callback = options;
if (!["object", "string"].includes(typeof(options))) options = undefined;
}
try {
Remote.filesystem.writeFile(path, data, options);
callback(null);
}
catch (error) {
callback(error);
}
};
export const writeFileSync = function (path, data, options) {
Remote.filesystem.writeFile(path, data, options);
};
export const readdir = function (path, options, callback) {
try {
const result = Remote.filesystem.readDirectory(path, options);
callback(null, result);
}
catch (error) {
callback(error, null);
}
};
export const readdirSync = function (path, options) {
return Remote.filesystem.readDirectory(path, options);
};
export const mkdir = function (path, options, callback) {
try {
const result = Remote.filesystem.createDirectory(path, options);
callback(null, result);
}
catch (error) {
callback(error, null);
}
};
export const mkdirSync = function (path, options) {
Remote.filesystem.createDirectory(path, options);
};
export const rmdir = function (path, options, callback) {
try {
const result = Remote.filesystem.deleteDirectory(path, options);
callback(null, result);
}
catch (error) {
callback(error, null);
}
};
export const rmdirSync = function (path, options) {
Remote.filesystem.deleteDirectory(path, options);
};
export const exists = function (path, options, callback) {
try {
const result = Remote.filesystem.exists(path, options);
callback(null, result);
}
catch (error) {
callback(error, null);
}
};
export const existsSync = function (path, options) {
return Remote.filesystem.exists(path, options);
};
export const stat = function (path, options, callback) {
try {
const result = Remote.filesystem.getStats(path, options);
callback(null, result);
}
catch (error) {
callback(error);
}
};
export const statSync = function (path, options) {
return Remote.filesystem.getStats(path, options);
};
export const lstat = stat;
export const lstatSync = statSync;
export const rename = function (oldPath, newPath, options, callback) {
try {
const result = Remote.filesystem.rename(oldPath, newPath, options);
callback(null, result);
}
catch (error) {
callback(error, null);
}
};
export const renameSync = function (oldPath, newPath, options) {
return Remote.filesystem.renameSync(oldPath, newPath, options);
};
export const realpath = function (path, options, callback) {
try {
const result = Remote.filesystem.getStats(path, options);
callback(null, result);
}
catch (error) {
callback(error, null);
}
};
export const realpathSync = function (path, options) {
return Remote.filesystem.getRealPath(path, options);
};
export const watch = (path, options, callback) => {
return Remote.filesystem.watch(path, options, callback);
};
export const createWriteStream = (path, options) => {
return Remote.filesystem.createWriteStream(path, options);
};
export default {
readFile,
exists,
existsSync,
lstat,
lstatSync,
mkdir,
mkdirSync,
readFileSync,
readdir,
readdirSync,
realpath,
realpathSync,
rename,
renameSync,
rmdir,
rmdirSync,
watch,
writeFile,
writeFileSync,
createWriteStream
};

View File

@ -0,0 +1,23 @@
import EventEmitter from "common/events";
import Remote from "./remote";
export function get(url, options = {}, callback) {
if (typeof(options) === "function") {
callback = options;
options = null;
}
const emitter = new EventEmitter();
callback(emitter);
Remote.https.get(url, options, (error, res, body) => {
if (error) return emitter.emit("error", error);
emitter.emit("data", body);
emitter.emit("end", res);
});
return emitter;
}
export default {get};

View File

@ -0,0 +1,45 @@
import Module from "./module";
import * as vm from "./vm";
import * as fs from "./fs";
import request from "./request";
import EventEmitter from "common/events";
import * as https from "./https";
import Buffer from "./buffer";
import crypto from "./crypto";
import Remote from "./remote";
const originalFs = Object.assign({}, fs);
originalFs.writeFileSync = (path, data, options) => fs.writeFileSync(path, data, Object.assign({}, options, {originalFs: true}));
originalFs.writeFile = (path, data, options) => fs.writeFile(path, data, Object.assign({}, options, {originalFs: true}));
export const createRequire = function (path) {
return mod => {
switch (mod) {
case "request": return request;
case "https": return https;
case "original-fs": return originalFs;
case "fs": return fs;
case "path": return Remote.path;
case "events": return EventEmitter;
case "electron": return Remote.electron;
case "process": return window.process;
case "vm": return vm;
case "module": return Module;
case "buffer": return Buffer.getBuffer();
case "crypto": return crypto;
default:
return Module._load(mod, path, createRequire);
}
};
};
const require = window.require = createRequire(".");
require.cache = {};
require.resolve = (path) => {
for (const key of Object.keys(require.cache)) {
if (key.startsWith(path)) return require.cache[key];
}
};
export default require;

View File

@ -0,0 +1,103 @@
import Logger from "common/logger";
import {compileFunction} from "./vm";
import Remote from "./remote";
import fs from "./fs";
const path = Remote.path;
export const RequireExtensions = {
".js": (module, filename) => {
const fileContent = Remote.filesystem.readFile(filename, "utf8");
module.fileContent = fileContent;
module._compile(fileContent);
return module.exports;
},
".json": (module, filename) => {
const fileContent = Remote.filesystem.readFile(filename, "utf8");
module.fileContent = fileContent;
module.exports = JSON.parse(fileContent);
return module.exports;
}
};
export default class Module {
static resolveMainFile(mod, basePath) {
const parent = path.extname(basePath) ? path.dirname(basePath) : basePath;
const files = Remote.filesystem.readDirectory(parent);
if (!Array.isArray(files)) return null;
for (const file of files) {
const ext = path.extname(file);
if (file === "package.json") {
const pkg = require(path.resolve(parent, file));
if (!Reflect.has(pkg, "main")) continue;
return path.resolve(parent, pkg.main);
}
if (path.slice(0, -ext.length) == "index" && RequireExtensions[ext]) return mod;
}
}
static getExtension(mod) {
return path.extname(mod) || Reflect.ownKeys(RequireExtensions).find(e => Remote.filesystem.exists(mod + e));
}
static getFilePath(basePath, mod) {
if (!path.isAbsolute(mod)) mod = path.resolve(basePath, mod);
const defaultExtension = path.extname(mod);
if (!defaultExtension) {
const ext = Reflect.ownKeys(RequireExtensions).find(e => Remote.filesystem.exists(mod + e));
if (ext) {
mod = mod + ext;
}
}
return fs.realpathSync(mod);
}
static _load(mod, basePath, createRequire) {
const originalReq = mod;
if (!path.isAbsolute(mod)) mod = path.resolve(basePath, mod);
const filePath = this.getFilePath(basePath, mod);
if (!Remote.filesystem.exists(filePath)) throw new Error(`Cannot find module ${mod}`);
if (window.require.cache[filePath]) return window.require.cache[filePath].exports;
const stats = Remote.filesystem.getStats(filePath);
if (stats.isDirectory()) mod = this.resolveMainFile(mod, basePath);
const ext = this.getExtension(filePath);
const loader = RequireExtensions[ext];
if (!loader) throw new Error(`Cannot find module ${originalReq}`);
const module = window.require.cache[mod] = new Module(filePath, internalModule, createRequire(mod));
loader(module, filePath);
return module.exports;
}
static get Module() {return Module;}
static get createRequire() {return Logger.warn("ContextModule", "Module.createRequire not implemented yet.");}
static get _extensions() {return RequireExtensions;}
constructor(id, parent, require) {
this.id = id;
this.path = Remote.path.dirname(id);
this.exports = {};
this.parent = parent;
this.filename = id;
this.loaded = false;
this.children = [];
this.require = require;
if (parent) parent.children.push(this);
}
_compile(code) {
const wrapped = compileFunction(code, ["require", "module", "exports", "__filename", "__dirname", "global"], this.filename);
wrapped(this.require, this, this.exports, this.filename, this.path, window);
}
}
const internalModule = new Module(".", null);

View File

@ -0,0 +1,3 @@
/** @type {import("../../../preload/src/api/index")} */
const RemoteAPI = window.BetterDiscordPreload(); // eslint-disable-line new-cap
export default RemoteAPI;

View File

@ -0,0 +1,55 @@
import Remote from "./remote";
const methods = ["get", "put", "post", "delete", "head"];
const aliases = {del: "delete"};
function parseArguments() {
let url, options, callback;
for (const arg of arguments) {
switch (typeof arg) {
case (arg !== null && "object"):
options = arg;
if ("url" in options) {
url = options.url;
}
break;
case (!url && "string"):
url = arg;
break;
case (!callback && "function"):
callback = arg;
break;
}
}
return {url, options, callback};
}
function validOptions(url, callback) {
return typeof url === "string" && typeof callback === "function";
}
export default function request() {
const {url, options = {}, callback} = parseArguments.apply(this, arguments);
if (!validOptions(url, callback)) return null;
if ("method" in options && methods.indexOf(options.method.toLowerCase()) >= 0) {
return Remote.https[options.method](url, options, callback);
}
return Remote.https.default(url, options, callback);
}
Object.assign(request, Object.fromEntries(
methods.concat(Object.keys(aliases)).map(method => [method, function () {
const {url, options = {}, callback} = parseArguments.apply(this, arguments);
if (!validOptions(url, callback)) return null;
return Remote.https[aliases[method] || method](url, options, callback);
}])
));

View File

@ -0,0 +1,3 @@
export const compileFunction = function (code, params = [], filename = "") {
return window.eval(`(${params.join(", ")}) => {${code}//# sourceURL=${filename.replace(/\\/g, "\\")}\n}`); // eslint-disable-line no-eval
};