summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/Snowflake.js145
-rw-r--r--src/Util.ts38
-rw-r--r--src/routes/api/v8/channel/#CHANNELID/followers.ts0
-rw-r--r--src/routes/api/v8/channel/#CHANNELID/invites.ts0
-rw-r--r--src/routes/api/v8/channel/#CHANNELID/messages.ts0
-rw-r--r--src/routes/api/v8/channel/#CHANNELID/permissions.ts0
-rw-r--r--src/routes/api/v8/channel/#CHANNELID/pins.ts0
-rw-r--r--src/routes/api/v8/channel/#CHANNELID/recipients.ts0
-rw-r--r--src/routes/api/v8/channel/#CHANNELID/typing.ts0
-rw-r--r--src/routes/api/v8/guilds/templates/index.ts0
-rw-r--r--src/routes/api/v8/invite/index.ts0
-rw-r--r--src/routes/assets/index.ts4
12 files changed, 187 insertions, 0 deletions
diff --git a/src/Snowflake.js b/src/Snowflake.js
new file mode 100644
index 00000000..feb5eb41
--- /dev/null
+++ b/src/Snowflake.js
@@ -0,0 +1,145 @@
+// @ts-nocheck
+
+// github.com/discordjs/discord.js/blob/master/src/util/Snowflake.js
+"use strict";
+
+// Discord epoch (2015-01-01T00:00:00.000Z)
+const EPOCH = 1420070400000;
+let INCREMENT = 0;
+
+/**
+ * A container for useful snowflake-related methods.
+ */
+class SnowflakeUtil {
+	constructor() {
+		throw new Error(`The ${this.constructor.name} class may not be instantiated.`);
+	}
+
+	/**
+	 * A Twitter snowflake, except the epoch is 2015-01-01T00:00:00.000Z
+	 * ```
+	 * If we have a snowflake '266241948824764416' we can represent it as binary:
+	 *
+	 * 64                                          22     17     12          0
+	 *  000000111011000111100001101001000101000000  00001  00000  000000000000
+	 *       number of ms since Discord epoch       worker  pid    increment
+	 * ```
+	 * @typedef {string} Snowflake
+	 */
+
+	/**
+	 * Transforms a snowflake from a decimal string to a bit string.
+	 * @param  {Snowflake} num Snowflake to be transformed
+	 * @returns {string}
+	 * @private
+	 */
+	static idToBinary(num) {
+		let bin = "";
+		let high = parseInt(num.slice(0, -10)) || 0;
+		let low = parseInt(num.slice(-10));
+		while (low > 0 || high > 0) {
+			bin = String(low & 1) + bin;
+			low = Math.floor(low / 2);
+			if (high > 0) {
+				low += 5000000000 * (high % 2);
+				high = Math.floor(high / 2);
+			}
+		}
+		return bin;
+	}
+
+	/**
+	 * Transforms a snowflake from a bit string to a decimal string.
+	 * @param  {string} num Bit string to be transformed
+	 * @returns {Snowflake}
+	 * @private
+	 */
+	static binaryToID(num) {
+		let dec = "";
+
+		while (num.length > 50) {
+			const high = parseInt(num.slice(0, -32), 2);
+			const low = parseInt((high % 10).toString(2) + num.slice(-32), 2);
+
+			dec = (low % 10).toString() + dec;
+			num =
+				Math.floor(high / 10).toString(2) +
+				Math.floor(low / 10)
+					.toString(2)
+					.padStart(32, "0");
+		}
+
+		num = parseInt(num, 2);
+		while (num > 0) {
+			dec = (num % 10).toString() + dec;
+			num = Math.floor(num / 10);
+		}
+
+		return dec;
+	}
+
+	/**
+	 * Generates a Discord snowflake.
+	 * <info>This hardcodes the worker ID as 1 and the process ID as 0.</info>
+	 * @param {number|Date} [timestamp=Date.now()] Timestamp or date of the snowflake to generate
+	 * @returns {Snowflake} The generated snowflake
+	 */
+	static generate(timestamp = Date.now()) {
+		if (timestamp instanceof Date) timestamp = timestamp.getTime();
+		if (typeof timestamp !== "number" || isNaN(timestamp)) {
+			throw new TypeError(
+				`"timestamp" argument must be a number (received ${isNaN(timestamp) ? "NaN" : typeof timestamp})`
+			);
+		}
+		if (INCREMENT >= 4095) INCREMENT = 0;
+		const BINARY = `${(timestamp - EPOCH).toString(2).padStart(42, "0")}0000100000${(INCREMENT++)
+			.toString(2)
+			.padStart(12, "0")}`;
+		return SnowflakeUtil.binaryToID(BINARY);
+	}
+
+	/**
+	 * A deconstructed snowflake.
+	 * @typedef {Object} DeconstructedSnowflake
+	 * @property {number} timestamp Timestamp the snowflake was created
+	 * @property {Date} date Date the snowflake was created
+	 * @property {number} workerID Worker ID in the snowflake
+	 * @property {number} processID Process ID in the snowflake
+	 * @property {number} increment Increment in the snowflake
+	 * @property {string} binary Binary representation of the snowflake
+	 */
+
+	/**
+	 * Deconstructs a Discord snowflake.
+	 * @param {Snowflake} snowflake Snowflake to deconstruct
+	 * @returns {DeconstructedSnowflake} Deconstructed snowflake
+	 */
+	static deconstruct(snowflake) {
+		const BINARY = SnowflakeUtil.idToBinary(snowflake).toString(2).padStart(64, "0");
+		const res = {
+			timestamp: parseInt(BINARY.substring(0, 42), 2) + EPOCH,
+			workerID: parseInt(BINARY.substring(42, 47), 2),
+			processID: parseInt(BINARY.substring(47, 52), 2),
+			increment: parseInt(BINARY.substring(52, 64), 2),
+			binary: BINARY,
+		};
+		Object.defineProperty(res, "date", {
+			get: function get() {
+				return new Date(this.timestamp);
+			},
+			enumerable: true,
+		});
+		return res;
+	}
+
+	/**
+	 * Discord's epoch value (2015-01-01T00:00:00.000Z).
+	 * @type {number}
+	 * @readonly
+	 */
+	static get EPOCH() {
+		return EPOCH;
+	}
+}
+
+module.exports = SnowflakeUtil;
diff --git a/src/Util.ts b/src/Util.ts
new file mode 100644
index 00000000..291372c1
--- /dev/null
+++ b/src/Util.ts
@@ -0,0 +1,38 @@
+import fs from "fs/promises";
+import "missing-native-js-functions";
+
+export interface traverseDirectoryOptions {
+	dirname: string;
+	filter?: RegExp;
+	excludeDirs?: RegExp;
+	recursive?: boolean;
+}
+
+const DEFAULT_EXCLUDE_DIR = /^\./;
+const DEFAULT_FILTER = /^([^\.].*)\.js$/;
+
+export async function traverseDirectory<T>(
+	options: traverseDirectoryOptions,
+	action: (path: string) => T
+): Promise<T[]> {
+	if (!options.filter) options.filter = DEFAULT_FILTER;
+	if (!options.excludeDirs) options.excludeDirs = DEFAULT_EXCLUDE_DIR;
+
+	const routes = await fs.readdir(options.dirname);
+	const promises = <Promise<T | T[] | undefined>[]>routes.map(async (file) => {
+		const path = options.dirname + file;
+		const stat = await fs.lstat(path);
+		if (path.match(<RegExp>options.excludeDirs)) return;
+
+		if (stat.isFile() && path.match(<RegExp>options.filter)) {
+			return action(path);
+		} else if (options.recursive && stat.isDirectory()) {
+			return traverseDirectory({ ...options, dirname: path + "/" }, action);
+		}
+	});
+	const result = await Promise.all(promises);
+
+	const t = <(T | undefined)[]>result.flat();
+
+	return <T[]>t.filter((x) => x != undefined);
+}
diff --git a/src/routes/api/v8/channel/#CHANNELID/followers.ts b/src/routes/api/v8/channel/#CHANNELID/followers.ts
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/routes/api/v8/channel/#CHANNELID/followers.ts
diff --git a/src/routes/api/v8/channel/#CHANNELID/invites.ts b/src/routes/api/v8/channel/#CHANNELID/invites.ts
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/routes/api/v8/channel/#CHANNELID/invites.ts
diff --git a/src/routes/api/v8/channel/#CHANNELID/messages.ts b/src/routes/api/v8/channel/#CHANNELID/messages.ts
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/routes/api/v8/channel/#CHANNELID/messages.ts
diff --git a/src/routes/api/v8/channel/#CHANNELID/permissions.ts b/src/routes/api/v8/channel/#CHANNELID/permissions.ts
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/routes/api/v8/channel/#CHANNELID/permissions.ts
diff --git a/src/routes/api/v8/channel/#CHANNELID/pins.ts b/src/routes/api/v8/channel/#CHANNELID/pins.ts
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/routes/api/v8/channel/#CHANNELID/pins.ts
diff --git a/src/routes/api/v8/channel/#CHANNELID/recipients.ts b/src/routes/api/v8/channel/#CHANNELID/recipients.ts
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/routes/api/v8/channel/#CHANNELID/recipients.ts
diff --git a/src/routes/api/v8/channel/#CHANNELID/typing.ts b/src/routes/api/v8/channel/#CHANNELID/typing.ts
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/routes/api/v8/channel/#CHANNELID/typing.ts
diff --git a/src/routes/api/v8/guilds/templates/index.ts b/src/routes/api/v8/guilds/templates/index.ts
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/routes/api/v8/guilds/templates/index.ts
diff --git a/src/routes/api/v8/invite/index.ts b/src/routes/api/v8/invite/index.ts
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/routes/api/v8/invite/index.ts
diff --git a/src/routes/assets/index.ts b/src/routes/assets/index.ts
index d3683f43..c2b9f2b0 100644
--- a/src/routes/assets/index.ts
+++ b/src/routes/assets/index.ts
@@ -1,3 +1,7 @@
+/**
+ * * patch to redirect requests from cloned client
+ * (../../client/index.html)
+ */
 import { Router } from "express";
 import fetch from "node-fetch";