diff --git a/.eslintrc.json b/.eslintrc.json
index 43e4cefb..d10b8722 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -2,7 +2,7 @@
"root": true,
"parser": "@typescript-eslint/parser",
"ignorePatterns": ["dist", "browser"],
- "plugins": ["header", "simple-import-sort"],
+ "plugins": ["header", "simple-import-sort", "unused-imports"],
"rules": {
// Since it's only been a month and Vencord has already been stolen
// by random skids who rebranded it to "AlphaCord" and erased all license
@@ -86,6 +86,8 @@
"prefer-spread": "error",
"simple-import-sort/imports": "error",
- "simple-import-sort/exports": "error"
+ "simple-import-sort/exports": "error",
+
+ "unused-imports/no-unused-imports": "error"
}
}
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index c56cf5a5..951bb606 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -28,7 +28,7 @@ jobs:
run: pnpm buildWeb
- name: Build
- run: pnpm build
+ run: pnpm build --standalone
- name: Get some values needed for the release
id: vars
diff --git a/package.json b/package.json
index f73c457b..7cab94ed 100644
--- a/package.json
+++ b/package.json
@@ -42,6 +42,7 @@
"eslint": "^8.24.0",
"eslint-plugin-header": "^3.1.1",
"eslint-plugin-simple-import-sort": "^8.0.0",
+ "eslint-plugin-unused-imports": "^2.0.0",
"standalone-electron-types": "^1.0.0",
"type-fest": "^3.1.0",
"typescript": "^4.8.4"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 8a1483b6..924d0ec2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -11,6 +11,7 @@ specifiers:
eslint: ^8.24.0
eslint-plugin-header: ^3.1.1
eslint-plugin-simple-import-sort: ^8.0.0
+ eslint-plugin-unused-imports: ^2.0.0
fflate: ^0.7.4
standalone-electron-types: ^1.0.0
type-fest: ^3.1.0
@@ -30,6 +31,7 @@ devDependencies:
eslint: 8.24.0
eslint-plugin-header: 3.1.1_eslint@8.24.0
eslint-plugin-simple-import-sort: 8.0.0_eslint@8.24.0
+ eslint-plugin-unused-imports: 2.0.0_eslint@8.24.0
standalone-electron-types: 1.0.0
type-fest: 3.1.0
typescript: 4.8.4
@@ -582,6 +584,25 @@ packages:
eslint: 8.24.0
dev: true
+ /eslint-plugin-unused-imports/2.0.0_eslint@8.24.0:
+ resolution: {integrity: sha512-3APeS/tQlTrFa167ThtP0Zm0vctjr4M44HMpeg1P4bK6wItarumq0Ma82xorMKdFsWpphQBlRPzw/pxiVELX1A==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ '@typescript-eslint/eslint-plugin': ^5.0.0
+ eslint: ^8.0.0
+ peerDependenciesMeta:
+ '@typescript-eslint/eslint-plugin':
+ optional: true
+ dependencies:
+ eslint: 8.24.0
+ eslint-rule-composer: 0.3.0
+ dev: true
+
+ /eslint-rule-composer/0.3.0:
+ resolution: {integrity: sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==}
+ engines: {node: '>=4.0.0'}
+ dev: true
+
/eslint-scope/7.1.1:
resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
diff --git a/scripts/build/build.mjs b/scripts/build/build.mjs
index 163f4ceb..bbf81053 100755
--- a/scripts/build/build.mjs
+++ b/scripts/build/build.mjs
@@ -18,7 +18,22 @@
*/
import esbuild from "esbuild";
-import { commonOpts, fileIncludePlugin, gitHashPlugin, globPlugins, makeAllPackagesExternalPlugin } from "./common.mjs";
+
+import { commonOpts, gitHash, globPlugins, isStandalone } from "./common.mjs";
+
+const defines = {
+ IS_STANDALONE: isStandalone
+};
+if (defines.IS_STANDALONE === "false")
+ // If this is a local build (not standalone), optimise
+ // for the specific platform we're on
+ defines["process.platform"] = JSON.stringify(process.platform);
+
+const header = `
+// Vencord ${gitHash}
+// Standalone: ${defines.IS_STANDALONE}
+// Platform: ${defines["process.platform"] || "Universal"}
+`.trim();
/**
* @type {esbuild.BuildOptions}
@@ -30,8 +45,11 @@ const nodeCommonOpts = {
target: ["esnext"],
minify: true,
bundle: true,
- sourcemap: "linked",
- external: ["electron"]
+ external: ["electron", ...commonOpts.external],
+ define: defines,
+ banner: {
+ js: header
+ }
};
await Promise.all([
@@ -39,11 +57,15 @@ await Promise.all([
...nodeCommonOpts,
entryPoints: ["src/preload.ts"],
outfile: "dist/preload.js",
+ footer: { js: "//# sourceURL=VencordPreload\n//# sourceMappingURL=vencord://preload.js.map" },
+ sourcemap: "external",
}),
esbuild.build({
...nodeCommonOpts,
entryPoints: ["src/patcher.ts"],
outfile: "dist/patcher.js",
+ footer: { js: "//# sourceURL=VencordPatcher\n//# sourceMappingURL=vencord://patcher.js.map" },
+ sourcemap: "external",
}),
esbuild.build({
...commonOpts,
@@ -51,16 +73,16 @@ await Promise.all([
outfile: "dist/renderer.js",
format: "iife",
target: ["esnext"],
- footer: { js: "//# sourceURL=VencordRenderer" },
+ footer: { js: "//# sourceURL=VencordRenderer\n//# sourceMappingURL=vencord://renderer.js.map" },
globalName: "Vencord",
- external: ["plugins", "git-hash"],
+ sourcemap: "external",
plugins: [
globPlugins,
- gitHashPlugin,
- fileIncludePlugin
+ ...commonOpts.plugins
],
define: {
- IS_WEB: "false"
+ IS_WEB: "false",
+ IS_STANDALONE: isStandalone
}
}),
]).catch(err => {
diff --git a/scripts/build/buildWeb.mjs b/scripts/build/buildWeb.mjs
index 009d5e85..f0197b72 100755
--- a/scripts/build/buildWeb.mjs
+++ b/scripts/build/buildWeb.mjs
@@ -26,7 +26,7 @@ import { join } from "path";
// wtf is this assert syntax
import PackageJSON from "../../package.json" assert { type: "json" };
-import { commonOpts, fileIncludePlugin, gitHashPlugin, globPlugins } from "./common.mjs";
+import { commonOpts, fileIncludePlugin, gitHashPlugin, gitRemotePlugin, globPlugins } from "./common.mjs";
/**
* @type {esbuild.BuildOptions}
@@ -40,11 +40,13 @@ const commonOptions = {
plugins: [
globPlugins,
gitHashPlugin,
+ gitRemotePlugin,
fileIncludePlugin
],
target: ["esnext"],
define: {
- IS_WEB: "true"
+ IS_WEB: "true",
+ IS_STANDALONE: "true"
}
};
diff --git a/scripts/build/common.mjs b/scripts/build/common.mjs
index c3afc7ff..db871349 100644
--- a/scripts/build/common.mjs
+++ b/scripts/build/common.mjs
@@ -16,13 +16,15 @@
* along with this program. If not, see .
*/
-import { execSync } from "child_process";
+import { exec, execSync } from "child_process";
import esbuild from "esbuild";
import { existsSync } from "fs";
import { readdir, readFile } from "fs/promises";
import { join } from "path";
+import { promisify } from "util";
-const watch = process.argv.includes("--watch");
+export const watch = process.argv.includes("--watch");
+export const isStandalone = JSON.stringify(process.argv.includes("--standalone"));
// https://github.com/evanw/esbuild/issues/619#issuecomment-751995294
/**
@@ -42,14 +44,15 @@ export const makeAllPackagesExternalPlugin = {
export const globPlugins = {
name: "glob-plugins",
setup: build => {
- build.onResolve({ filter: /^plugins$/ }, args => {
+ const filter = /^~plugins$/;
+ build.onResolve({ filter }, args => {
return {
namespace: "import-plugins",
path: args.path
};
});
- build.onLoad({ filter: /^plugins$/, namespace: "import-plugins" }, async () => {
+ build.onLoad({ filter, namespace: "import-plugins" }, async () => {
const pluginDirs = ["plugins", "userplugins"];
let code = "";
let plugins = "\n";
@@ -76,14 +79,14 @@ export const globPlugins = {
}
};
-const gitHash = execSync("git rev-parse --short HEAD", { encoding: "utf-8" }).trim();
+export const gitHash = execSync("git rev-parse --short HEAD", { encoding: "utf-8" }).trim();
/**
* @type {esbuild.Plugin}
*/
export const gitHashPlugin = {
name: "git-hash-plugin",
setup: build => {
- const filter = /^git-hash$/;
+ const filter = /^~git-hash$/;
build.onResolve({ filter }, args => ({
namespace: "git-hash", path: args.path
}));
@@ -93,13 +96,35 @@ export const gitHashPlugin = {
}
};
+/**
+ * @type {esbuild.Plugin}
+ */
+export const gitRemotePlugin = {
+ name: "git-remote-plugin",
+ setup: build => {
+ const filter = /^~git-remote$/;
+ build.onResolve({ filter }, args => ({
+ namespace: "git-remote", path: args.path
+ }));
+ build.onLoad({ filter, namespace: "git-remote" }, async () => {
+ const res = await promisify(exec)("git remote get-url origin", { encoding: "utf-8" });
+ const remote = res.stdout.trim()
+ .replace("https://github.com/", "")
+ .replace("git@github.com:", "")
+ .replace(/.git$/, "");
+
+ return { contents: `export default "${remote}"` };
+ });
+ }
+};
+
/**
* @type {esbuild.Plugin}
*/
export const fileIncludePlugin = {
name: "file-include-plugin",
setup: build => {
- const filter = /^@fileContent\/.+$/;
+ const filter = /^~fileContent\/.+$/;
build.onResolve({ filter }, args => ({
namespace: "include-file",
path: args.path,
@@ -126,5 +151,6 @@ export const commonOpts = {
minify: !watch,
sourcemap: watch ? "inline" : "",
legalComments: "linked",
- plugins: [fileIncludePlugin]
+ plugins: [fileIncludePlugin, gitHashPlugin, gitRemotePlugin],
+ external: ["~plugins", "~git-hash", "~git-remote"]
};
diff --git a/src/api/Commands/index.ts b/src/api/Commands/index.ts
index c7034ab3..3b42379d 100644
--- a/src/api/Commands/index.ts
+++ b/src/api/Commands/index.ts
@@ -18,7 +18,7 @@
import { makeCodeblock } from "../../utils/misc";
import { generateId, sendBotMessage } from "./commandHelpers";
-import { ApplicationCommandInputType, ApplicationCommandType, Argument, Command, CommandContext, CommandReturnValue,Option } from "./types";
+import { ApplicationCommandInputType, ApplicationCommandType, Argument, Command, CommandContext, Option } from "./types";
export * from "./commandHelpers";
export * from "./types";
diff --git a/src/api/settings.ts b/src/api/settings.ts
index 0fdbe137..5d581c63 100644
--- a/src/api/settings.ts
+++ b/src/api/settings.ts
@@ -16,7 +16,7 @@
* along with this program. If not, see .
*/
-import plugins from "plugins";
+import plugins from "~plugins";
import IpcEvents from "../utils/IpcEvents";
import { mergeDefaults } from "../utils/misc";
diff --git a/src/components/Monaco.ts b/src/components/Monaco.ts
index 33f5545d..e1471593 100644
--- a/src/components/Monaco.ts
+++ b/src/components/Monaco.ts
@@ -16,7 +16,7 @@
* along with this program. If not, see .
*/
-import monacoHtml from "@fileContent/monacoWin.html";
+import monacoHtml from "~fileContent/monacoWin.html";
import { IpcEvents } from "../utils";
import { debounce } from "../utils/debounce";
diff --git a/src/components/PluginSettings/index.tsx b/src/components/PluginSettings/index.tsx
index 578c0e07..6ad9750a 100644
--- a/src/components/PluginSettings/index.tsx
+++ b/src/components/PluginSettings/index.tsx
@@ -16,7 +16,7 @@
* along with this program. If not, see .
*/
-import Plugins from "plugins";
+import Plugins from "~plugins";
import { showNotice } from "../../api/Notices";
import { Settings, useSettings } from "../../api/settings";
diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx
index 8ffe1113..e720c6fb 100644
--- a/src/components/Settings.tsx
+++ b/src/components/Settings.tsx
@@ -50,7 +50,6 @@ export default ErrorBoundary.wrap(function Settings() {
}));
}, []);
-
return (
diff --git a/src/components/Updater.tsx b/src/components/Updater.tsx
index 21ae6a3f..a11d65b8 100644
--- a/src/components/Updater.tsx
+++ b/src/components/Updater.tsx
@@ -16,10 +16,10 @@
* along with this program. If not, see .
*/
-import gitHash from "git-hash";
+import gitHash from "~git-hash";
import { classes, useAwaiter } from "../utils/misc";
-import { changes, checkForUpdates, getRepo, isNewer,isOutdated, rebuild, update, updateError, UpdateLogger } from "../utils/updater";
+import { changes, checkForUpdates, getRepo, isNewer, rebuild, update, updateError, UpdateLogger } from "../utils/updater";
import { Alerts, Button, Card, Forms, Margins, Parser, React, Toasts } from "../webpack/common";
import ErrorBoundary from "./ErrorBoundary";
import { ErrorCard } from "./ErrorCard";
diff --git a/src/globals.d.ts b/src/globals.d.ts
index d1be8d8b..56145439 100644
--- a/src/globals.d.ts
+++ b/src/globals.d.ts
@@ -31,6 +31,8 @@ declare global {
* replace: `${IS_WEB}?foo:bar`
*/
export var IS_WEB: boolean;
+ export var IS_STANDALONE: boolean;
+
export var VencordNative: typeof import("./VencordNative").default;
export var Vencord: typeof import("./Vencord");
export var appSettings: {
diff --git a/src/ipcMain/extensions.ts b/src/ipcMain/extensions.ts
index d676f22d..0e26ff1d 100644
--- a/src/ipcMain/extensions.ts
+++ b/src/ipcMain/extensions.ts
@@ -19,33 +19,15 @@
import { session } from "electron";
import { unzip } from "fflate";
import { constants as fsConstants } from "fs";
-import { access,mkdir, rm, writeFile } from "fs/promises";
-import https from "https";
+import { access, mkdir, rm, writeFile } from "fs/promises";
import { join } from "path";
import { DATA_DIR } from "./constants";
import { crxToZip } from "./crxToZip";
+import { get } from "./simpleGet";
const extensionCacheDir = join(DATA_DIR, "ExtensionCache");
-function download(url: string) {
- return new Promise((resolve, reject) => {
- https.get(url, res => {
- const { statusCode, statusMessage, headers } = res;
- if (statusCode! >= 400)
- return void reject(`${statusCode}: ${statusMessage} - ${url}`);
- if (statusCode! >= 300)
- return void resolve(download(headers.location!));
-
- const chunks = [] as Buffer[];
- res.on("error", reject);
-
- res.on("data", chunk => chunks.push(chunk));
- res.once("end", () => resolve(Buffer.concat(chunks)));
- });
- });
-}
-
async function extract(data: Buffer, outDir: string) {
await mkdir(outDir, { recursive: true });
return new Promise((resolve, reject) => {
@@ -86,7 +68,7 @@ export async function installExt(id: string) {
await access(extDir, fsConstants.F_OK);
} catch (err) {
const url = `https://clients2.google.com/service/update2/crx?response=redirect&acceptformat=crx2,crx3&x=id%3D${id}%26uc&prodversion=32`;
- const buf = await download(url);
+ const buf = await get(url);
await extract(crxToZip(buf), extDir);
}
diff --git a/src/ipcMain/index.ts b/src/ipcMain/index.ts
index 958728a2..8a60bc6e 100644
--- a/src/ipcMain/index.ts
+++ b/src/ipcMain/index.ts
@@ -18,19 +18,18 @@
import "./updater";
-import monacoHtml from "@fileContent/../components/monacoWin.html;base64";
-import { app, BrowserWindow, desktopCapturer, ipcMain, shell } from "electron";
+import { BrowserWindow, desktopCapturer, ipcMain, shell } from "electron";
import { mkdirSync, readFileSync, watch } from "fs";
import { open, readFile, writeFile } from "fs/promises";
import { join } from "path";
+import monacoHtml from "~fileContent/../components/monacoWin.html;base64";
+
import { debounce } from "../utils/debounce";
import IpcEvents from "../utils/IpcEvents";
import { Queue } from "../utils/Queue";
import { ALLOWED_PROTOCOLS, QUICKCSS_PATH, SETTINGS_DIR, SETTINGS_FILE } from "./constants";
-
-
mkdirSync(SETTINGS_DIR, { recursive: true });
function readCss() {
diff --git a/src/ipcMain/simpleGet.ts b/src/ipcMain/simpleGet.ts
new file mode 100644
index 00000000..1a8302c0
--- /dev/null
+++ b/src/ipcMain/simpleGet.ts
@@ -0,0 +1,37 @@
+/*
+ * Vencord, a modification for Discord's desktop app
+ * Copyright (c) 2022 Vendicated and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+*/
+
+import https from "https";
+
+export function get(url: string, options: https.RequestOptions = {}) {
+ return new Promise((resolve, reject) => {
+ https.get(url, options, res => {
+ const { statusCode, statusMessage, headers } = res;
+ if (statusCode! >= 400)
+ return void reject(`${statusCode}: ${statusMessage} - ${url}`);
+ if (statusCode! >= 300)
+ return void resolve(get(headers.location!, options));
+
+ const chunks = [] as Buffer[];
+ res.on("error", reject);
+
+ res.on("data", chunk => chunks.push(chunk));
+ res.once("end", () => resolve(Buffer.concat(chunks)));
+ });
+ });
+}
diff --git a/src/ipcMain/updater/common.ts b/src/ipcMain/updater/common.ts
new file mode 100644
index 00000000..41f08e81
--- /dev/null
+++ b/src/ipcMain/updater/common.ts
@@ -0,0 +1,59 @@
+/*
+ * Vencord, a modification for Discord's desktop app
+ * Copyright (c) 2022 Vendicated and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+*/
+
+import { createHash } from "crypto";
+import { createReadStream } from "fs";
+import { join } from "path";
+
+export async function calculateHashes() {
+ const hashes = {} as Record;
+
+ await Promise.all(
+ ["patcher.js", "preload.js", "renderer.js"].map(file => new Promise(r => {
+ const fis = createReadStream(join(__dirname, file));
+ const hash = createHash("sha1", { encoding: "hex" });
+ fis.once("end", () => {
+ hash.end();
+ hashes[file] = hash.read();
+ r();
+ });
+ fis.pipe(hash);
+ }))
+ );
+
+ return hashes;
+}
+
+export function serializeErrors(func: (...args: any[]) => any) {
+ return async function () {
+ try {
+ return {
+ ok: true,
+ value: await func(...arguments)
+ };
+ } catch (e: any) {
+ return {
+ ok: false,
+ error: e instanceof Error ? {
+ // prototypes get lost, so turn error into plain object
+ ...e
+ } : e
+ };
+ }
+ };
+}
diff --git a/src/ipcMain/updater.ts b/src/ipcMain/updater/git.ts
similarity index 66%
rename from src/ipcMain/updater.ts
rename to src/ipcMain/updater/git.ts
index 69879168..7e4176a8 100644
--- a/src/ipcMain/updater.ts
+++ b/src/ipcMain/updater/git.ts
@@ -17,13 +17,12 @@
*/
import { execFile as cpExecFile } from "child_process";
-import { createHash } from "crypto";
import { ipcMain } from "electron";
-import { createReadStream } from "fs";
import { join } from "path";
import { promisify } from "util";
-import IpcEvents from "../utils/IpcEvents";
+import IpcEvents from "../../utils/IpcEvents";
+import { calculateHashes, serializeErrors } from "./common";
const VENCORD_SRC_DIR = join(__dirname, "..");
@@ -35,44 +34,6 @@ function git(...args: string[]) {
});
}
-async function calculateHashes() {
- const hashes = {} as Record;
-
- await Promise.all(
- ["patcher.js", "preload.js", "renderer.js"].map(file => new Promise(r => {
- const fis = createReadStream(join(__dirname, file));
- const hash = createHash("sha1", { encoding: "hex" });
- fis.once("end", () => {
- hash.end();
- hashes[file] = hash.read();
- r();
- });
- fis.pipe(hash);
- }))
- );
-
- return hashes;
-}
-
-function serializeErrors(func: (...args: any[]) => any) {
- return async function () {
- try {
- return {
- ok: true,
- value: await func(...arguments)
- };
- } catch (e: any) {
- return {
- ok: false,
- error: e instanceof Error ? {
- // prototypes get lost, so turn error into plain object
- ...e
- } : e
- };
- }
- };
-}
-
async function getRepo() {
const res = await git("remote", "get-url", "origin");
return res.stdout.trim()
diff --git a/src/ipcMain/updater/http.ts b/src/ipcMain/updater/http.ts
new file mode 100644
index 00000000..5b3f0ff5
--- /dev/null
+++ b/src/ipcMain/updater/http.ts
@@ -0,0 +1,86 @@
+/*
+ * Vencord, a modification for Discord's desktop app
+ * Copyright (c) 2022 Vendicated and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+*/
+
+import { ipcMain } from "electron";
+import { writeFile } from "fs/promises";
+import { join } from "path";
+
+import gitHash from "~git-hash";
+import gitRemote from "~git-remote";
+
+import { VENCORD_USER_AGENT } from "../../utils/constants";
+import IpcEvents from "../../utils/IpcEvents";
+import { get } from "../simpleGet";
+import { calculateHashes, serializeErrors } from "./common";
+
+const API_BASE = `https://api.github.com/repos/${gitRemote}`;
+let PendingUpdates = [] as [string, Buffer][];
+
+async function githubGet(endpoint: string) {
+ return get(API_BASE + endpoint, {
+ headers: {
+ Accept: "application/vnd.github+json",
+ // "All API requests MUST include a valid User-Agent header.
+ // Requests with no User-Agent header will be rejected."
+ "User-Agent": VENCORD_USER_AGENT,
+ // todo: perhaps add support for (optional) api token?
+ // unauthorised rate limit is 60 reqs/h
+ // https://github.com/settings/tokens/new?description=Vencord%20Updater
+ }
+ });
+}
+
+async function calculateGitChanges() {
+ const res = await githubGet(`/compare/${gitHash}...HEAD`);
+
+ const data = JSON.parse(res.toString("utf-8"));
+ return data.commits.map(c => ({
+ // github api only sends the long sha
+ hash: c.sha.slice(0, 7),
+ author: c.author.login,
+ message: c.commit.message
+ }));
+}
+
+async function fetchUpdates() {
+ const release = await githubGet("/releases/latest");
+
+ const data = JSON.parse(release.toString());
+ const hash = data.name.slice(data.name.lastIndexOf(" ") + 1);
+ if (hash === gitHash)
+ return true;
+
+ await Promise.all(data.assets.map(async ({ name, browser_download_url }) => {
+ if (["patcher.js", "preload.js", "renderer.js"].some(s => name.startsWith(s))) {
+ PendingUpdates.push([name, await get(browser_download_url)]);
+ }
+ }));
+ return true;
+}
+
+async function applyUpdates() {
+ await Promise.all(PendingUpdates.map(([name, data]) => writeFile(join(__dirname, name), data)));
+ PendingUpdates = [];
+ return true;
+}
+
+ipcMain.handle(IpcEvents.GET_HASHES, serializeErrors(calculateHashes));
+ipcMain.handle(IpcEvents.GET_REPO, serializeErrors(() => `https://github.com/${gitRemote}`));
+ipcMain.handle(IpcEvents.GET_UPDATES, serializeErrors(calculateGitChanges));
+ipcMain.handle(IpcEvents.UPDATE, serializeErrors(fetchUpdates));
+ipcMain.handle(IpcEvents.BUILD, serializeErrors(applyUpdates));
diff --git a/src/ipcMain/updater/index.ts b/src/ipcMain/updater/index.ts
new file mode 100644
index 00000000..70361129
--- /dev/null
+++ b/src/ipcMain/updater/index.ts
@@ -0,0 +1,19 @@
+/*
+ * Vencord, a modification for Discord's desktop app
+ * Copyright (c) 2022 Vendicated and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+*/
+
+import(IS_STANDALONE ? "./http" : "./git");
diff --git a/src/modules.d.ts b/src/modules.d.ts
index 70bad2f5..78cc9a52 100644
--- a/src/modules.d.ts
+++ b/src/modules.d.ts
@@ -19,17 +19,21 @@
// eslint-disable-next-line spaced-comment
///
-declare module "plugins" {
+declare module "~plugins" {
const plugins: Record;
export default plugins;
}
-declare module "git-hash" {
+declare module "~git-hash" {
const hash: string;
export default hash;
}
+declare module "~git-remote" {
+ const remote: string;
+ export default remote;
+}
-declare module "@fileContent/*" {
+declare module "~fileContent/*" {
const content: string;
export default content;
}
diff --git a/src/patcher.ts b/src/patcher.ts
index 11a70314..023c0af5 100644
--- a/src/patcher.ts
+++ b/src/patcher.ts
@@ -87,6 +87,22 @@ Object.defineProperty(global, "appSettings", {
process.env.DATA_DIR = join(app.getPath("userData"), "..", "Vencord");
electron.app.whenReady().then(() => {
+ // Source Maps! Maybe there's a better way but since the renderer is executed
+ // from a string I don't think any other form of sourcemaps would work
+ electron.protocol.registerFileProtocol("vencord", ({ url: unsafeUrl }, cb) => {
+ let url = unsafeUrl.slice("vencord://".length);
+ if (url.endsWith("/")) url = url.slice(0, -1);
+ switch (url) {
+ case "renderer.js.map":
+ case "preload.js.map":
+ case "patcher.js.map": // doubt
+ cb(join(__dirname, url));
+ break;
+ default:
+ cb({ statusCode: 403 });
+ }
+ });
+
try {
const settings = JSON.parse(readSettings());
if (settings.enableReactDevtools)
diff --git a/src/plugins/index.ts b/src/plugins/index.ts
index 2ce9c0f2..fdb256c5 100644
--- a/src/plugins/index.ts
+++ b/src/plugins/index.ts
@@ -16,7 +16,7 @@
* along with this program. If not, see .
*/
-import Plugins from "plugins";
+import Plugins from "~plugins";
import { registerCommand, unregisterCommand } from "../api/Commands";
import { Settings } from "../api/settings";
diff --git a/src/plugins/pronoundb/components/PronounsProfileWrapper.tsx b/src/plugins/pronoundb/components/PronounsProfileWrapper.tsx
index 930d5a76..3f0022e4 100644
--- a/src/plugins/pronoundb/components/PronounsProfileWrapper.tsx
+++ b/src/plugins/pronoundb/components/PronounsProfileWrapper.tsx
@@ -16,7 +16,7 @@
* along with this program. If not, see .
*/
-import { classes,useAwaiter } from "../../../utils";
+import { useAwaiter } from "../../../utils";
import { Settings } from "../../../Vencord";
import { UserStore } from "../../../webpack/common";
import { PronounMapping, UserProfileProps } from "../types";
diff --git a/src/plugins/pronoundb/utils.ts b/src/plugins/pronoundb/utils.ts
index 24bc3e2d..73ec7b6c 100644
--- a/src/plugins/pronoundb/utils.ts
+++ b/src/plugins/pronoundb/utils.ts
@@ -16,9 +16,8 @@
* along with this program. If not, see .
*/
-import gitHash from "git-hash";
-
-import { debounce } from "../../utils";
+import { VENCORD_USER_AGENT } from "../../utils/constants";
+import { debounce } from "../../utils/debounce";
import { Settings } from "../../Vencord";
import { PronounsFormat } from ".";
import { PronounCode, PronounMapping, PronounsResponse } from "./types";
@@ -64,7 +63,7 @@ async function bulkFetchPronouns(ids: string[]): Promise {
method: "GET",
headers: {
"Accept": "application/json",
- "X-PronounDB-Source": `Vencord/${gitHash} (github.com/Vendicated/Vencord)`
+ "X-PronounDB-Source": VENCORD_USER_AGENT
}
});
return await req.json()
diff --git a/src/plugins/sendify.ts b/src/plugins/sendify.ts
index d0c7af73..436a9287 100644
--- a/src/plugins/sendify.ts
+++ b/src/plugins/sendify.ts
@@ -16,9 +16,6 @@
* along with this program. If not, see .
*/
-import { Message } from "discord-types/general";
-import { PartialDeep } from "type-fest";
-
import { ApplicationCommandInputType, sendBotMessage } from "../api/Commands";
import { lazyWebpack } from "../utils";
import { Devs } from "../utils/constants";
@@ -27,33 +24,33 @@ import { filters } from "../webpack";
import { FluxDispatcher } from "../webpack/common";
interface Album {
- id: string
+ id: string;
image: {
- height: number
- width: number
- url: string
- }
- name: string
+ height: number;
+ width: number;
+ url: string;
+ };
+ name: string;
}
interface Artist {
external_urls: {
- spotify: string
- }
- href: string
- id: string
- name: string
- type: "artist" | string
- uri: string
+ spotify: string;
+ };
+ href: string;
+ id: string;
+ name: string;
+ type: "artist" | string;
+ uri: string;
}
interface Track {
- id: string
- album: Album
- artists: Artist[]
- duration: number
- isLocal: boolean
- name: string
+ id: string;
+ album: Album;
+ artists: Artist[];
+ duration: number;
+ isLocal: boolean;
+ name: string;
}
const Spotify = lazyWebpack(filters.byProps(["getPlayerState"]));
diff --git a/src/plugins/settings.ts b/src/plugins/settings.ts
index 56726b5b..df27ca12 100644
--- a/src/plugins/settings.ts
+++ b/src/plugins/settings.ts
@@ -1,6 +1,6 @@
/*
* Vencord, a modification for Discord's desktop app
- * Copyright (c) 2022 Vendicated and contributors
+ * Copyright (c) 2022 Vendicated and Megumin
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
* along with this program. If not, see .
*/
-import gitHash from "git-hash";
+import gitHash from "~git-hash";
import { Devs } from "../utils/constants";
import definePlugin from "../utils/types";
@@ -34,7 +34,13 @@ export default definePlugin({
replace: m => {
const idx = m.indexOf("Host") - 1;
const template = m.slice(0, idx);
- let r = `${m}, ${template}"Vencord ", "${gitHash}${IS_WEB ? " (Web)" : ""}"), " ")`;
+ const additionalInfo = IS_WEB
+ ? " (Web)"
+ : IS_STANDALONE
+ ? " (Standalone)"
+ : "";
+
+ let r = `${m}, ${template}"Vencord ", "${gitHash}${additionalInfo}"), " ")`;
if (!IS_WEB) {
r += `,${template} "Electron ",VencordNative.getVersions().electron)," "),`;
r += `${template} "Chrome ",VencordNative.getVersions().chrome)," ")`;
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
index eccd3e35..30c07ba3 100644
--- a/src/utils/constants.ts
+++ b/src/utils/constants.ts
@@ -16,8 +16,12 @@
* along with this program. If not, see .
*/
+import gitHash from "~git-hash";
+import gitRemote from "~git-remote";
+
export const WEBPACK_CHUNK = "webpackChunkdiscord_app";
export const REACT_GLOBAL = "Vencord.Webpack.Common.React";
+export const VENCORD_USER_AGENT = `Vencord/${gitHash}${gitRemote ? ` (https://github.com/${gitRemote})` : ""}`;
// Add yourself here if you made more than one plugin
export const Devs = Object.freeze({
diff --git a/src/utils/updater.ts b/src/utils/updater.ts
index 51739ae8..ea2319f9 100644
--- a/src/utils/updater.ts
+++ b/src/utils/updater.ts
@@ -16,7 +16,7 @@
* along with this program. If not, see .
*/
-import gitHash from "git-hash";
+import gitHash from "~git-hash";
import IpcEvents from "./IpcEvents";
import Logger from "./logger";