mirror of
https://github.com/spacebarchat/server.git
synced 2024-09-20 09:41:35 +02:00
✨ Util
This commit is contained in:
parent
4f9eb951ce
commit
76000f8fa1
17
.vscode/launch.json
vendored
17
.vscode/launch.json
vendored
@ -8,8 +8,17 @@
|
|||||||
"sourceMaps": true,
|
"sourceMaps": true,
|
||||||
"type": "node",
|
"type": "node",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Launch Program",
|
"name": "Launch Server",
|
||||||
"program": "${workspaceFolder}/dist/test/db_test.js",
|
"program": "${workspaceFolder}/dist/index.js",
|
||||||
|
"preLaunchTask": "tsc: build - tsconfig.json",
|
||||||
|
"outFiles": ["${workspaceFolder}/dist/**/*.js"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceMaps": true,
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Test",
|
||||||
|
"program": "${workspaceFolder}/dist/test/mongo_test.js",
|
||||||
"preLaunchTask": "tsc: build - tsconfig.json",
|
"preLaunchTask": "tsc: build - tsconfig.json",
|
||||||
"outFiles": ["${workspaceFolder}/dist/**/*.js"]
|
"outFiles": ["${workspaceFolder}/dist/**/*.js"]
|
||||||
},
|
},
|
||||||
@ -18,7 +27,9 @@
|
|||||||
"program": "${file}",
|
"program": "${file}",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"skipFiles": ["<node_internals>/**"],
|
"skipFiles": ["<node_internals>/**"],
|
||||||
"type": "node"
|
"runtimeArgs": ["--nolazy", "-r", "ts-node/register/transpile-only"],
|
||||||
|
"type": "node",
|
||||||
|
"resolveSourceMapLocations": ["${workspaceFolder}/**", "!**/node_modules/**"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
2628
package-lock.json
generated
2628
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@ -22,16 +22,24 @@
|
|||||||
"@types/node-fetch": "^2.5.7",
|
"@types/node-fetch": "^2.5.7",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-cache-middleware": "^1.0.1",
|
"express-cache-middleware": "^1.0.1",
|
||||||
|
"express-validator": "^6.9.2",
|
||||||
"faker": "^5.1.0",
|
"faker": "^5.1.0",
|
||||||
"lambert-db": "^1.0.3",
|
"jsonwebtoken": "^8.5.1",
|
||||||
"lambert-server": "^1.0.3",
|
"jwa": "^2.0.0",
|
||||||
"missing-native-js-functions": "^1.0.8",
|
"jws": "^4.0.0",
|
||||||
|
"lambert-db": "^1.1.0",
|
||||||
|
"lambert-server": "^1.0.8",
|
||||||
|
"missing-native-js-functions": "^1.1.6",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
"rethinkdb-ts": "^2.4.5"
|
"rethinkdb-ts": "^2.4.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/faker": "^5.1.5",
|
"@types/faker": "^5.1.5",
|
||||||
"@types/node": "^14.14.10",
|
"@types/jsonwebtoken": "^8.5.0",
|
||||||
|
"@types/jws": "^3.2.3",
|
||||||
|
"@types/node": "^14.14.22",
|
||||||
|
"lambert-server": "file:../../Trenite/Lambert-server",
|
||||||
|
"ts-node": "^9.1.1",
|
||||||
"typescript": "^4.1.2"
|
"typescript": "^4.1.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import fs from "fs/promises";
|
import fs from "fs/promises";
|
||||||
import { Server, ServerOptions } from "lambert-server";
|
import { Server, ServerOptions } from "lambert-server";
|
||||||
|
import { Authentication, GlobalRateLimit } from "./middlewares/";
|
||||||
|
import Config from "./util/Config";
|
||||||
|
import db from "./util/Database";
|
||||||
|
|
||||||
export interface DiscordServerOptions extends ServerOptions {}
|
export interface DiscordServerOptions extends ServerOptions {}
|
||||||
|
|
||||||
@ -19,6 +22,13 @@ export class DiscordServer extends Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
|
await db.init();
|
||||||
|
console.log("[DB] connected");
|
||||||
|
await Promise.all([Config.init()]);
|
||||||
|
|
||||||
|
this.app.use(GlobalRateLimit);
|
||||||
|
this.app.use(Authentication);
|
||||||
|
|
||||||
// recursively loads files in routes/
|
// recursively loads files in routes/
|
||||||
this.routes = await this.registerRoutes(__dirname + "/routes/");
|
this.routes = await this.registerRoutes(__dirname + "/routes/");
|
||||||
// const indexHTML = await (await fetch("https://discord.com/app")).buffer();
|
// const indexHTML = await (await fetch("https://discord.com/app")).buffer();
|
||||||
|
38
src/Util.ts
38
src/Util.ts
@ -1,38 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
38
src/Utils.ts
38
src/Utils.ts
@ -1,38 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
@ -1,3 +1,7 @@
|
|||||||
|
process.on("uncaughtException", console.error);
|
||||||
|
process.on("unhandledRejection", console.error);
|
||||||
|
setTimeout(() => {}, 100000000);
|
||||||
|
|
||||||
import { DiscordServer } from "./Server";
|
import { DiscordServer } from "./Server";
|
||||||
|
|
||||||
const server = new DiscordServer({ port: 3000 });
|
const server = new DiscordServer({ port: 3000 });
|
||||||
|
4
src/middlewares/index.ts
Normal file
4
src/middlewares/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { Authentication } from "./Authentication";
|
||||||
|
import { GlobalRateLimit } from "./GlobalRateLimit";
|
||||||
|
|
||||||
|
export { Authentication, GlobalRateLimit };
|
@ -1,59 +0,0 @@
|
|||||||
import { Snowflake } from "./Snowflake";
|
|
||||||
|
|
||||||
export interface Guild {
|
|
||||||
afkChannel?: Snowflake;
|
|
||||||
afkTimeout: number;
|
|
||||||
onlineCount: number;
|
|
||||||
available: boolean;
|
|
||||||
banner: string | null;
|
|
||||||
channels: GuildChannelManager;
|
|
||||||
readonly createdTimestamp: number;
|
|
||||||
defaultMessageNotifications: DefaultMessageNotifications | number;
|
|
||||||
deleted: boolean;
|
|
||||||
description: string | null;
|
|
||||||
discoverySplash: string | null;
|
|
||||||
embedChannel: GuildChannel | null;
|
|
||||||
embedChannelID: Snowflake | null;
|
|
||||||
embedEnabled: boolean;
|
|
||||||
emojis: GuildEmojiManager;
|
|
||||||
explicitContentFilter: ExplicitContentFilterLevel;
|
|
||||||
features: GuildFeatures[];
|
|
||||||
icon: string | null;
|
|
||||||
id: Snowflake;
|
|
||||||
joinedTimestamp: number;
|
|
||||||
large: boolean;
|
|
||||||
maximumMembers: number | null;
|
|
||||||
maximumPresences: number | null;
|
|
||||||
memberCount: number;
|
|
||||||
members: GuildMemberManager;
|
|
||||||
mfaLevel: number;
|
|
||||||
name: string;
|
|
||||||
readonly nameAcronym: string;
|
|
||||||
readonly owner: Snowflake | null;
|
|
||||||
ownerID: Snowflake;
|
|
||||||
readonly partnered: boolean;
|
|
||||||
preferredLocale: string;
|
|
||||||
premiumSubscriptionCount: number | null;
|
|
||||||
premiumTier: PremiumTier;
|
|
||||||
presences: PresenceManager;
|
|
||||||
readonly publicUpdatesChannel: TextChannel | null;
|
|
||||||
publicUpdatesChannelID: Snowflake | null;
|
|
||||||
region: string;
|
|
||||||
roles: RoleManager;
|
|
||||||
readonly rulesChannel: TextChannel | null;
|
|
||||||
rulesChannelID: Snowflake | null;
|
|
||||||
readonly shard: WebSocketShard;
|
|
||||||
shardID: number;
|
|
||||||
splash: string | null;
|
|
||||||
readonly systemChannel: TextChannel | null;
|
|
||||||
systemChannelFlags: Readonly<SystemChannelFlags>;
|
|
||||||
systemChannelID: Snowflake | null;
|
|
||||||
vanityURLCode: string | null;
|
|
||||||
vanityURLUses: number | null;
|
|
||||||
verificationLevel: VerificationLevel;
|
|
||||||
readonly verified: boolean;
|
|
||||||
readonly voiceStates: VoiceStateManager;
|
|
||||||
readonly widgetChannel: TextChannel | null;
|
|
||||||
widgetChannelID: Snowflake | null;
|
|
||||||
widgetEnabled: boolean | null;
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
export type Snowflake = string;
|
|
@ -0,0 +1,9 @@
|
|||||||
|
import { Request, Response, Router } from "express";
|
||||||
|
import { check } from "../../../../util/instanceOf";
|
||||||
|
const router: Router = Router();
|
||||||
|
|
||||||
|
router.post("/", check({ test: String, $user: String }), (req: Request, res: Response) => {
|
||||||
|
res.send("OK");
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
@ -0,0 +1,4 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
const router: Router = Router();
|
||||||
|
|
||||||
|
export default router;
|
@ -0,0 +1,4 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
const router: Router = Router();
|
||||||
|
|
||||||
|
export default router;
|
@ -0,0 +1,4 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
const router: Router = Router();
|
||||||
|
|
||||||
|
export default router;
|
@ -0,0 +1,4 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
const router: Router = Router();
|
||||||
|
|
||||||
|
export default router;
|
@ -0,0 +1,4 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
const router: Router = Router();
|
||||||
|
|
||||||
|
export default router;
|
@ -0,0 +1,4 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
const router: Router = Router();
|
||||||
|
|
||||||
|
export default router;
|
@ -0,0 +1,4 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
const router: Router = Router();
|
||||||
|
|
||||||
|
export default router;
|
@ -0,0 +1,4 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
const router: Router = Router();
|
||||||
|
|
||||||
|
export default router;
|
@ -0,0 +1,4 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
const router: Router = Router();
|
||||||
|
|
||||||
|
export default router;
|
@ -0,0 +1,4 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
const router: Router = Router();
|
||||||
|
|
||||||
|
export default router;
|
@ -0,0 +1,4 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
const router: Router = Router();
|
||||||
|
|
||||||
|
export default router;
|
@ -0,0 +1,4 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
const router: Router = Router();
|
||||||
|
|
||||||
|
export default router;
|
@ -3,10 +3,10 @@
|
|||||||
* (../../client/index.html)
|
* (../../client/index.html)
|
||||||
*/
|
*/
|
||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
import fetch from "node-fetch";
|
import fetch, { Response } from "node-fetch";
|
||||||
|
|
||||||
const router = Router();
|
const router: Router = Router();
|
||||||
const cache = new Map();
|
const cache = new Map<string, Response>();
|
||||||
const assetEndpoint = "https://discord.com/assets/";
|
const assetEndpoint = "https://discord.com/assets/";
|
||||||
|
|
||||||
export async function getCache(key: string): Promise<Response> {
|
export async function getCache(key: string): Promise<Response> {
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
import { r } from "rethinkdb-ts";
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
const connection = await r.connect({ port: 28015, host: "192.168.178.122" });
|
|
||||||
|
|
||||||
r.db("test");
|
|
||||||
}
|
|
||||||
|
|
||||||
main();
|
|
37
src/test/jwt.ts
Normal file
37
src/test/jwt.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
const jwa = require("jwa");
|
||||||
|
|
||||||
|
var STR64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".split("");
|
||||||
|
|
||||||
|
function base64url(string: string, encoding: string) {
|
||||||
|
// @ts-ignore
|
||||||
|
return Buffer.from(string, encoding).toString("base64").replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
||||||
|
}
|
||||||
|
|
||||||
|
function to64String(input: number, current = ""): string {
|
||||||
|
if (input < 0 && current.length == 0) {
|
||||||
|
input = input * -1;
|
||||||
|
}
|
||||||
|
var modify = input % 64;
|
||||||
|
var remain = Math.floor(input / 64);
|
||||||
|
var result = STR64[modify] + current;
|
||||||
|
return remain <= 0 ? result : to64String(remain, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
function to64Parse(input: string) {
|
||||||
|
var result = 0;
|
||||||
|
var toProc = input.split("");
|
||||||
|
var e;
|
||||||
|
for (e in toProc) {
|
||||||
|
result = result * 64 + STR64.indexOf(toProc[e]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const start = `${base64url("311129357362135041")}.${to64String(Date.now())}`;
|
||||||
|
const signature = jwa("HS256").sign(start, `test`);
|
||||||
|
const token = `${start}.${signature}`;
|
||||||
|
console.log(token);
|
||||||
|
|
||||||
|
// MzExMTI5MzU3MzYyMTM1MDQx.XdQb_rA.907VgF60kocnOTl32MSUWGSSzbAytQ0jbt36KjLaxuY
|
||||||
|
// MzExMTI5MzU3MzYyMTM1MDQx.XdQbaPy.4vGx4L7IuFJGsRe6IL3BeybLIvbx4Vauvx12pwNsy2U
|
8
src/test/jwt2.ts
Normal file
8
src/test/jwt2.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import jwt from "jsonwebtoken";
|
||||||
|
|
||||||
|
// console.log(jwt.sign("test", "test"));
|
||||||
|
|
||||||
|
jwt.verify(`${"2WmFS_EAdYFCBOFM9pVPo9g4bpuI2I9U_JGTCfrx7Tk".repeat(1000000)}`, "test", (err, decoded) => {
|
||||||
|
if (err) console.error(err);
|
||||||
|
console.log(decoded);
|
||||||
|
});
|
14
src/test/mongo_test.ts
Normal file
14
src/test/mongo_test.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import mongoose from "mongoose";
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const mongoConnection = await mongoose.createConnection(
|
||||||
|
"mongodb://localhost:27017/lambert?readPreference=secondaryPreferred",
|
||||||
|
{
|
||||||
|
useNewUrlParser: true,
|
||||||
|
useUnifiedTopology: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
console.log("connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
34
src/test/rethink_test.ts
Normal file
34
src/test/rethink_test.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { r } from "rethinkdb-ts";
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const connection = await r.connect({ port: 28015 });
|
||||||
|
|
||||||
|
const db = r.db("test");
|
||||||
|
const cursor = await db
|
||||||
|
.table("guilds")
|
||||||
|
.get(0)
|
||||||
|
.changes({ squash: true })
|
||||||
|
.map(function (row) {
|
||||||
|
return row("old_val")
|
||||||
|
.keys()
|
||||||
|
.setUnion(row("new_val").keys())
|
||||||
|
.concatMap(function (key) {
|
||||||
|
return r.branch(
|
||||||
|
row("old_val")(key).ne(row("new_val")(key)).default(true),
|
||||||
|
[[key, row("new_val")(key).default(null)]],
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.coerceTo("object");
|
||||||
|
})
|
||||||
|
.run(connection);
|
||||||
|
|
||||||
|
console.log("each");
|
||||||
|
cursor.each(function (err, row) {
|
||||||
|
if (err) throw err;
|
||||||
|
console.log(row);
|
||||||
|
});
|
||||||
|
console.log("eachend");
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
146
src/util/BitField.ts
Normal file
146
src/util/BitField.ts
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
// https://github.com/discordjs/discord.js/blob/master/src/util/BitField.js
|
||||||
|
// Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah
|
||||||
|
|
||||||
|
export type BitFieldResolvable = number | BitField | string | BitFieldResolvable[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data structure that makes it easy to interact with a bitfield.
|
||||||
|
*/
|
||||||
|
export class BitField {
|
||||||
|
public bitfield: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Numeric bitfield flags.
|
||||||
|
* <info>Defined in extension classes</info>
|
||||||
|
*/
|
||||||
|
public static FLAGS: Record<string, number>;
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
constructor(bits: BitFieldResolvable = 0) {
|
||||||
|
/**
|
||||||
|
* Bitfield of the packed bits
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
this.bitfield = BitField.resolve(bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the bitfield has a bit, or any of multiple bits.
|
||||||
|
*/
|
||||||
|
any(bit: BitFieldResolvable): boolean {
|
||||||
|
return (this.bitfield & BitField.resolve(bit)) !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this bitfield equals another
|
||||||
|
*/
|
||||||
|
equals(bit: BitFieldResolvable): boolean {
|
||||||
|
return this.bitfield === BitField.resolve(bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the bitfield has a bit, or multiple bits.
|
||||||
|
*/
|
||||||
|
has(bit: BitFieldResolvable): boolean {
|
||||||
|
if (Array.isArray(bit)) return bit.every((p) => this.has(p));
|
||||||
|
bit = BitField.resolve(bit);
|
||||||
|
return (this.bitfield & bit) === bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all given bits that are missing from the bitfield.
|
||||||
|
*/
|
||||||
|
missing(bits: BitFieldResolvable) {
|
||||||
|
if (!Array.isArray(bits)) bits = new BitField(bits).toArray();
|
||||||
|
return bits.filter((p) => !this.has(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Freezes these bits, making them immutable.
|
||||||
|
*/
|
||||||
|
freeze(): Readonly<BitField> {
|
||||||
|
return Object.freeze(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds bits to these ones.
|
||||||
|
* @param {...BitFieldResolvable} [bits] Bits to add
|
||||||
|
* @returns {BitField} These bits or new BitField if the instance is frozen.
|
||||||
|
*/
|
||||||
|
add(...bits: BitFieldResolvable[]): BitField {
|
||||||
|
let total = 0;
|
||||||
|
for (const bit of bits) {
|
||||||
|
total |= BitField.resolve(bit);
|
||||||
|
}
|
||||||
|
if (Object.isFrozen(this)) return new BitField(this.bitfield | total);
|
||||||
|
this.bitfield |= total;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes bits from these.
|
||||||
|
* @param {...BitFieldResolvable} [bits] Bits to remove
|
||||||
|
*/
|
||||||
|
remove(...bits: BitFieldResolvable[]) {
|
||||||
|
let total = 0;
|
||||||
|
for (const bit of bits) {
|
||||||
|
total |= BitField.resolve(bit);
|
||||||
|
}
|
||||||
|
if (Object.isFrozen(this)) return new BitField(this.bitfield & ~total);
|
||||||
|
this.bitfield &= ~total;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an object mapping field names to a {@link boolean} indicating whether the
|
||||||
|
* bit is available.
|
||||||
|
* @param {...*} hasParams Additional parameters for the has method, if any
|
||||||
|
*/
|
||||||
|
serialize() {
|
||||||
|
const serialized: Record<string, boolean> = {};
|
||||||
|
for (const [flag, bit] of Object.entries(BitField.FLAGS)) serialized[flag] = this.has(bit);
|
||||||
|
return serialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an {@link Array} of bitfield names based on the bits available.
|
||||||
|
*/
|
||||||
|
toArray(): string[] {
|
||||||
|
return Object.keys(BitField.FLAGS).filter((bit) => this.has(bit));
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return this.bitfield;
|
||||||
|
}
|
||||||
|
|
||||||
|
valueOf() {
|
||||||
|
return this.bitfield;
|
||||||
|
}
|
||||||
|
|
||||||
|
*[Symbol.iterator]() {
|
||||||
|
yield* this.toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data that can be resolved to give a bitfield. This can be:
|
||||||
|
* * A bit number (this can be a number literal or a value taken from {@link BitField.FLAGS})
|
||||||
|
* * An instance of BitField
|
||||||
|
* * An Array of BitFieldResolvable
|
||||||
|
* @typedef {number|BitField|BitFieldResolvable[]} BitFieldResolvable
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves bitfields to their numeric form.
|
||||||
|
* @param {BitFieldResolvable} [bit=0] - bit(s) to resolve
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
static resolve(bit: BitFieldResolvable = 0): number {
|
||||||
|
if (typeof bit === "number" && bit >= 0) return bit;
|
||||||
|
if (bit instanceof BitField) return bit.bitfield;
|
||||||
|
if (Array.isArray(bit)) return bit.map((p) => this.resolve(p)).reduce((prev, p) => prev | p, 0);
|
||||||
|
if (typeof bit === "string" && typeof this.FLAGS[bit] !== "undefined") return this.FLAGS[bit];
|
||||||
|
throw new RangeError("BITFIELD_INVALID: " + bit);
|
||||||
|
}
|
||||||
|
}
|
25
src/util/Config.ts
Normal file
25
src/util/Config.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import "missing-native-js-functions";
|
||||||
|
import db from "./Database";
|
||||||
|
import { DefaultOptions } from "./Constants";
|
||||||
|
import { ProviderCache } from "lambert-db";
|
||||||
|
var Config: ProviderCache;
|
||||||
|
|
||||||
|
async function init() {
|
||||||
|
Config = db.data.config.cache();
|
||||||
|
await Config.init();
|
||||||
|
await Config.set(DefaultOptions.merge(Config.cache));
|
||||||
|
}
|
||||||
|
|
||||||
|
function get() {
|
||||||
|
return <DefaultOptions>Config.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
function set(val: any) {
|
||||||
|
return Config.set(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
init,
|
||||||
|
get: get,
|
||||||
|
set: set,
|
||||||
|
};
|
679
src/util/Constants.ts
Normal file
679
src/util/Constants.ts
Normal file
@ -0,0 +1,679 @@
|
|||||||
|
import crypto from "crypto";
|
||||||
|
import { VerifyOptions } from "jsonwebtoken";
|
||||||
|
|
||||||
|
export interface DefaultOptions {
|
||||||
|
user: {
|
||||||
|
maxGuilds: number;
|
||||||
|
maxUsername: number;
|
||||||
|
maxFriends: number;
|
||||||
|
};
|
||||||
|
guild: {
|
||||||
|
maxRoles: number;
|
||||||
|
maxMembers: number;
|
||||||
|
maxChannels: number;
|
||||||
|
maxChannelsInCategory: number;
|
||||||
|
hideOfflineMember: number;
|
||||||
|
};
|
||||||
|
message: {
|
||||||
|
characters: number;
|
||||||
|
ttsCharacters: number;
|
||||||
|
maxReactions: number;
|
||||||
|
maxAttachmentSize: number;
|
||||||
|
};
|
||||||
|
channel: {
|
||||||
|
maxPins: number;
|
||||||
|
maxTopic: number;
|
||||||
|
};
|
||||||
|
server: {
|
||||||
|
jwtSecret: string;
|
||||||
|
ipRateLimit: {
|
||||||
|
enabled: boolean;
|
||||||
|
count: number;
|
||||||
|
timespan: number;
|
||||||
|
};
|
||||||
|
forwadedFor: false | string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DefaultOptions: DefaultOptions = {
|
||||||
|
user: {
|
||||||
|
maxGuilds: 100,
|
||||||
|
maxUsername: 32,
|
||||||
|
maxFriends: 1000,
|
||||||
|
},
|
||||||
|
guild: {
|
||||||
|
maxRoles: 250,
|
||||||
|
maxMembers: 250000,
|
||||||
|
maxChannels: 500,
|
||||||
|
maxChannelsInCategory: 50,
|
||||||
|
hideOfflineMember: 1000,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
characters: 2000,
|
||||||
|
ttsCharacters: 200,
|
||||||
|
maxReactions: 20,
|
||||||
|
maxAttachmentSize: 8388608,
|
||||||
|
},
|
||||||
|
channel: {
|
||||||
|
maxPins: 50,
|
||||||
|
maxTopic: 1024,
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
jwtSecret: crypto.randomBytes(256).toString("base64"),
|
||||||
|
ipRateLimit: {
|
||||||
|
enabled: true,
|
||||||
|
count: 1000,
|
||||||
|
timespan: 1000 * 60 * 10,
|
||||||
|
},
|
||||||
|
forwadedFor: false,
|
||||||
|
// forwadedFor: "X-Forwarded-For" // nginx/reverse proxy
|
||||||
|
// forwadedFor: "CF-Connecting-IP" // cloudflare:
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const JWTOptions: VerifyOptions = { algorithms: ["HS256"] };
|
||||||
|
|
||||||
|
export const WSCodes = {
|
||||||
|
1000: "WS_CLOSE_REQUESTED",
|
||||||
|
4004: "TOKEN_INVALID",
|
||||||
|
4010: "SHARDING_INVALID",
|
||||||
|
4011: "SHARDING_REQUIRED",
|
||||||
|
4013: "INVALID_INTENTS",
|
||||||
|
4014: "DISALLOWED_INTENTS",
|
||||||
|
};
|
||||||
|
|
||||||
|
const AllowedImageFormats = ["webp", "png", "jpg", "jpeg", "gif"];
|
||||||
|
|
||||||
|
const AllowedImageSizes = Array.from({ length: 9 }, (e, i) => 2 ** (i + 4));
|
||||||
|
|
||||||
|
function makeImageUrl(root: string, { format = "webp", size = 512 } = {}) {
|
||||||
|
if (format && !AllowedImageFormats.includes(format)) throw new Error("IMAGE_FORMAT: " + format);
|
||||||
|
if (size && !AllowedImageSizes.includes(size)) throw new RangeError("IMAGE_SIZE: " + size);
|
||||||
|
return `${root}.${format}${size ? `?size=${size}` : ""}`;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Options for Image URLs.
|
||||||
|
* @typedef {Object} ImageURLOptions
|
||||||
|
* @property {string} [format] One of `webp`, `png`, `jpg`, `jpeg`, `gif`. If no format is provided,
|
||||||
|
* defaults to `webp`.
|
||||||
|
* @property {boolean} [dynamic] If true, the format will dynamically change to `gif` for
|
||||||
|
* animated avatars; the default is false.
|
||||||
|
* @property {number} [size] One of `16`, `32`, `64`, `128`, `256`, `512`, `1024`, `2048`, `4096`
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const Endpoints = {
|
||||||
|
CDN(root: string) {
|
||||||
|
return {
|
||||||
|
Emoji: (emojiID: string, format = "png") => `${root}/emojis/${emojiID}.${format}`,
|
||||||
|
Asset: (name: string) => `${root}/assets/${name}`,
|
||||||
|
DefaultAvatar: (discriminator: string) => `${root}/embed/avatars/${discriminator}.png`,
|
||||||
|
Avatar: (userID: string, hash: string, format = "webp", size: number, dynamic = false) => {
|
||||||
|
if (dynamic) format = hash.startsWith("a_") ? "gif" : format;
|
||||||
|
return makeImageUrl(`${root}/avatars/${userID}/${hash}`, { format, size });
|
||||||
|
},
|
||||||
|
Banner: (guildID: string, hash: string, format = "webp", size: number) =>
|
||||||
|
makeImageUrl(`${root}/banners/${guildID}/${hash}`, { format, size }),
|
||||||
|
Icon: (guildID: string, hash: string, format = "webp", size: number, dynamic = false) => {
|
||||||
|
if (dynamic) format = hash.startsWith("a_") ? "gif" : format;
|
||||||
|
return makeImageUrl(`${root}/icons/${guildID}/${hash}`, { format, size });
|
||||||
|
},
|
||||||
|
AppIcon: (
|
||||||
|
clientID: string,
|
||||||
|
hash: string,
|
||||||
|
{ format = "webp", size }: { format?: string; size?: number } = {}
|
||||||
|
) => makeImageUrl(`${root}/app-icons/${clientID}/${hash}`, { size, format }),
|
||||||
|
AppAsset: (
|
||||||
|
clientID: string,
|
||||||
|
hash: string,
|
||||||
|
{ format = "webp", size }: { format?: string; size?: number } = {}
|
||||||
|
) => makeImageUrl(`${root}/app-assets/${clientID}/${hash}`, { size, format }),
|
||||||
|
GDMIcon: (channelID: string, hash: string, format = "webp", size: number) =>
|
||||||
|
makeImageUrl(`${root}/channel-icons/${channelID}/${hash}`, { size, format }),
|
||||||
|
Splash: (guildID: string, hash: string, format = "webp", size: number) =>
|
||||||
|
makeImageUrl(`${root}/splashes/${guildID}/${hash}`, { size, format }),
|
||||||
|
DiscoverySplash: (guildID: string, hash: string, format = "webp", size: number) =>
|
||||||
|
makeImageUrl(`${root}/discovery-splashes/${guildID}/${hash}`, { size, format }),
|
||||||
|
TeamIcon: (
|
||||||
|
teamID: string,
|
||||||
|
hash: string,
|
||||||
|
{ format = "webp", size }: { format?: string; size?: number } = {}
|
||||||
|
) => makeImageUrl(`${root}/team-icons/${teamID}/${hash}`, { size, format }),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
invite: (root: string, code: string) => `${root}/${code}`,
|
||||||
|
botGateway: "/gateway/bot",
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current status of the client. Here are the available statuses:
|
||||||
|
* * READY: 0
|
||||||
|
* * CONNECTING: 1
|
||||||
|
* * RECONNECTING: 2
|
||||||
|
* * IDLE: 3
|
||||||
|
* * NEARLY: 4
|
||||||
|
* * DISCONNECTED: 5
|
||||||
|
* * WAITING_FOR_GUILDS: 6
|
||||||
|
* * IDENTIFYING: 7
|
||||||
|
* * RESUMING: 8
|
||||||
|
* @typedef {number} Status
|
||||||
|
*/
|
||||||
|
export const Status = {
|
||||||
|
READY: 0,
|
||||||
|
CONNECTING: 1,
|
||||||
|
RECONNECTING: 2,
|
||||||
|
IDLE: 3,
|
||||||
|
NEARLY: 4,
|
||||||
|
DISCONNECTED: 5,
|
||||||
|
WAITING_FOR_GUILDS: 6,
|
||||||
|
IDENTIFYING: 7,
|
||||||
|
RESUMING: 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current status of a voice connection. Here are the available statuses:
|
||||||
|
* * CONNECTED: 0
|
||||||
|
* * CONNECTING: 1
|
||||||
|
* * AUTHENTICATING: 2
|
||||||
|
* * RECONNECTING: 3
|
||||||
|
* * DISCONNECTED: 4
|
||||||
|
* @typedef {number} VoiceStatus
|
||||||
|
*/
|
||||||
|
export const VoiceStatus = {
|
||||||
|
CONNECTED: 0,
|
||||||
|
CONNECTING: 1,
|
||||||
|
AUTHENTICATING: 2,
|
||||||
|
RECONNECTING: 3,
|
||||||
|
DISCONNECTED: 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const OPCodes = {
|
||||||
|
DISPATCH: 0,
|
||||||
|
HEARTBEAT: 1,
|
||||||
|
IDENTIFY: 2,
|
||||||
|
STATUS_UPDATE: 3,
|
||||||
|
VOICE_STATE_UPDATE: 4,
|
||||||
|
VOICE_GUILD_PING: 5,
|
||||||
|
RESUME: 6,
|
||||||
|
RECONNECT: 7,
|
||||||
|
REQUEST_GUILD_MEMBERS: 8,
|
||||||
|
INVALID_SESSION: 9,
|
||||||
|
HELLO: 10,
|
||||||
|
HEARTBEAT_ACK: 11,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const VoiceOPCodes = {
|
||||||
|
IDENTIFY: 0,
|
||||||
|
SELECT_PROTOCOL: 1,
|
||||||
|
READY: 2,
|
||||||
|
HEARTBEAT: 3,
|
||||||
|
SESSION_DESCRIPTION: 4,
|
||||||
|
SPEAKING: 5,
|
||||||
|
HELLO: 8,
|
||||||
|
CLIENT_CONNECT: 12,
|
||||||
|
CLIENT_DISCONNECT: 13,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Events = {
|
||||||
|
RATE_LIMIT: "rateLimit",
|
||||||
|
CLIENT_READY: "ready",
|
||||||
|
GUILD_CREATE: "guildCreate",
|
||||||
|
GUILD_DELETE: "guildDelete",
|
||||||
|
GUILD_UPDATE: "guildUpdate",
|
||||||
|
GUILD_UNAVAILABLE: "guildUnavailable",
|
||||||
|
GUILD_AVAILABLE: "guildAvailable",
|
||||||
|
GUILD_MEMBER_ADD: "guildMemberAdd",
|
||||||
|
GUILD_MEMBER_REMOVE: "guildMemberRemove",
|
||||||
|
GUILD_MEMBER_UPDATE: "guildMemberUpdate",
|
||||||
|
GUILD_MEMBER_AVAILABLE: "guildMemberAvailable",
|
||||||
|
GUILD_MEMBER_SPEAKING: "guildMemberSpeaking",
|
||||||
|
GUILD_MEMBERS_CHUNK: "guildMembersChunk",
|
||||||
|
GUILD_INTEGRATIONS_UPDATE: "guildIntegrationsUpdate",
|
||||||
|
GUILD_ROLE_CREATE: "roleCreate",
|
||||||
|
GUILD_ROLE_DELETE: "roleDelete",
|
||||||
|
INVITE_CREATE: "inviteCreate",
|
||||||
|
INVITE_DELETE: "inviteDelete",
|
||||||
|
GUILD_ROLE_UPDATE: "roleUpdate",
|
||||||
|
GUILD_EMOJI_CREATE: "emojiCreate",
|
||||||
|
GUILD_EMOJI_DELETE: "emojiDelete",
|
||||||
|
GUILD_EMOJI_UPDATE: "emojiUpdate",
|
||||||
|
GUILD_BAN_ADD: "guildBanAdd",
|
||||||
|
GUILD_BAN_REMOVE: "guildBanRemove",
|
||||||
|
CHANNEL_CREATE: "channelCreate",
|
||||||
|
CHANNEL_DELETE: "channelDelete",
|
||||||
|
CHANNEL_UPDATE: "channelUpdate",
|
||||||
|
CHANNEL_PINS_UPDATE: "channelPinsUpdate",
|
||||||
|
MESSAGE_CREATE: "message",
|
||||||
|
MESSAGE_DELETE: "messageDelete",
|
||||||
|
MESSAGE_UPDATE: "messageUpdate",
|
||||||
|
MESSAGE_BULK_DELETE: "messageDeleteBulk",
|
||||||
|
MESSAGE_REACTION_ADD: "messageReactionAdd",
|
||||||
|
MESSAGE_REACTION_REMOVE: "messageReactionRemove",
|
||||||
|
MESSAGE_REACTION_REMOVE_ALL: "messageReactionRemoveAll",
|
||||||
|
MESSAGE_REACTION_REMOVE_EMOJI: "messageReactionRemoveEmoji",
|
||||||
|
USER_UPDATE: "userUpdate",
|
||||||
|
PRESENCE_UPDATE: "presenceUpdate",
|
||||||
|
VOICE_SERVER_UPDATE: "voiceServerUpdate",
|
||||||
|
VOICE_STATE_UPDATE: "voiceStateUpdate",
|
||||||
|
VOICE_BROADCAST_SUBSCRIBE: "subscribe",
|
||||||
|
VOICE_BROADCAST_UNSUBSCRIBE: "unsubscribe",
|
||||||
|
TYPING_START: "typingStart",
|
||||||
|
TYPING_STOP: "typingStop",
|
||||||
|
WEBHOOKS_UPDATE: "webhookUpdate",
|
||||||
|
ERROR: "error",
|
||||||
|
WARN: "warn",
|
||||||
|
DEBUG: "debug",
|
||||||
|
SHARD_DISCONNECT: "shardDisconnect",
|
||||||
|
SHARD_ERROR: "shardError",
|
||||||
|
SHARD_RECONNECTING: "shardReconnecting",
|
||||||
|
SHARD_READY: "shardReady",
|
||||||
|
SHARD_RESUME: "shardResume",
|
||||||
|
INVALIDATED: "invalidated",
|
||||||
|
RAW: "raw",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ShardEvents = {
|
||||||
|
CLOSE: "close",
|
||||||
|
DESTROYED: "destroyed",
|
||||||
|
INVALID_SESSION: "invalidSession",
|
||||||
|
READY: "ready",
|
||||||
|
RESUMED: "resumed",
|
||||||
|
ALL_READY: "allReady",
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of Structure allowed to be a partial:
|
||||||
|
* * USER
|
||||||
|
* * CHANNEL (only affects DMChannels)
|
||||||
|
* * GUILD_MEMBER
|
||||||
|
* * MESSAGE
|
||||||
|
* * REACTION
|
||||||
|
* <warn>Partials require you to put checks in place when handling data, read the Partials topic listed in the
|
||||||
|
* sidebar for more information.</warn>
|
||||||
|
* @typedef {string} PartialType
|
||||||
|
*/
|
||||||
|
export const PartialTypes = keyMirror(["USER", "CHANNEL", "GUILD_MEMBER", "MESSAGE", "REACTION"]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of a websocket message event, e.g. `MESSAGE_CREATE`. Here are the available events:
|
||||||
|
* * READY
|
||||||
|
* * RESUMED
|
||||||
|
* * GUILD_CREATE
|
||||||
|
* * GUILD_DELETE
|
||||||
|
* * GUILD_UPDATE
|
||||||
|
* * INVITE_CREATE
|
||||||
|
* * INVITE_DELETE
|
||||||
|
* * GUILD_MEMBER_ADD
|
||||||
|
* * GUILD_MEMBER_REMOVE
|
||||||
|
* * GUILD_MEMBER_UPDATE
|
||||||
|
* * GUILD_MEMBERS_CHUNK
|
||||||
|
* * GUILD_INTEGRATIONS_UPDATE
|
||||||
|
* * GUILD_ROLE_CREATE
|
||||||
|
* * GUILD_ROLE_DELETE
|
||||||
|
* * GUILD_ROLE_UPDATE
|
||||||
|
* * GUILD_BAN_ADD
|
||||||
|
* * GUILD_BAN_REMOVE
|
||||||
|
* * GUILD_EMOJIS_UPDATE
|
||||||
|
* * CHANNEL_CREATE
|
||||||
|
* * CHANNEL_DELETE
|
||||||
|
* * CHANNEL_UPDATE
|
||||||
|
* * CHANNEL_PINS_UPDATE
|
||||||
|
* * MESSAGE_CREATE
|
||||||
|
* * MESSAGE_DELETE
|
||||||
|
* * MESSAGE_UPDATE
|
||||||
|
* * MESSAGE_DELETE_BULK
|
||||||
|
* * MESSAGE_REACTION_ADD
|
||||||
|
* * MESSAGE_REACTION_REMOVE
|
||||||
|
* * MESSAGE_REACTION_REMOVE_ALL
|
||||||
|
* * MESSAGE_REACTION_REMOVE_EMOJI
|
||||||
|
* * USER_UPDATE
|
||||||
|
* * PRESENCE_UPDATE
|
||||||
|
* * TYPING_START
|
||||||
|
* * VOICE_STATE_UPDATE
|
||||||
|
* * VOICE_SERVER_UPDATE
|
||||||
|
* * WEBHOOKS_UPDATE
|
||||||
|
* @typedef {string} WSEventType
|
||||||
|
*/
|
||||||
|
export const WSEvents = keyMirror([
|
||||||
|
"READY",
|
||||||
|
"RESUMED",
|
||||||
|
"GUILD_CREATE",
|
||||||
|
"GUILD_DELETE",
|
||||||
|
"GUILD_UPDATE",
|
||||||
|
"INVITE_CREATE",
|
||||||
|
"INVITE_DELETE",
|
||||||
|
"GUILD_MEMBER_ADD",
|
||||||
|
"GUILD_MEMBER_REMOVE",
|
||||||
|
"GUILD_MEMBER_UPDATE",
|
||||||
|
"GUILD_MEMBERS_CHUNK",
|
||||||
|
"GUILD_INTEGRATIONS_UPDATE",
|
||||||
|
"GUILD_ROLE_CREATE",
|
||||||
|
"GUILD_ROLE_DELETE",
|
||||||
|
"GUILD_ROLE_UPDATE",
|
||||||
|
"GUILD_BAN_ADD",
|
||||||
|
"GUILD_BAN_REMOVE",
|
||||||
|
"GUILD_EMOJIS_UPDATE",
|
||||||
|
"CHANNEL_CREATE",
|
||||||
|
"CHANNEL_DELETE",
|
||||||
|
"CHANNEL_UPDATE",
|
||||||
|
"CHANNEL_PINS_UPDATE",
|
||||||
|
"MESSAGE_CREATE",
|
||||||
|
"MESSAGE_DELETE",
|
||||||
|
"MESSAGE_UPDATE",
|
||||||
|
"MESSAGE_DELETE_BULK",
|
||||||
|
"MESSAGE_REACTION_ADD",
|
||||||
|
"MESSAGE_REACTION_REMOVE",
|
||||||
|
"MESSAGE_REACTION_REMOVE_ALL",
|
||||||
|
"MESSAGE_REACTION_REMOVE_EMOJI",
|
||||||
|
"USER_UPDATE",
|
||||||
|
"PRESENCE_UPDATE",
|
||||||
|
"TYPING_START",
|
||||||
|
"VOICE_STATE_UPDATE",
|
||||||
|
"VOICE_SERVER_UPDATE",
|
||||||
|
"WEBHOOKS_UPDATE",
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of a message, e.g. `DEFAULT`. Here are the available types:
|
||||||
|
* * DEFAULT
|
||||||
|
* * RECIPIENT_ADD
|
||||||
|
* * RECIPIENT_REMOVE
|
||||||
|
* * CALL
|
||||||
|
* * CHANNEL_NAME_CHANGE
|
||||||
|
* * CHANNEL_ICON_CHANGE
|
||||||
|
* * PINS_ADD
|
||||||
|
* * GUILD_MEMBER_JOIN
|
||||||
|
* * USER_PREMIUM_GUILD_SUBSCRIPTION
|
||||||
|
* * USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1
|
||||||
|
* * USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2
|
||||||
|
* * USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3
|
||||||
|
* * CHANNEL_FOLLOW_ADD
|
||||||
|
* * GUILD_DISCOVERY_DISQUALIFIED
|
||||||
|
* * GUILD_DISCOVERY_REQUALIFIED
|
||||||
|
* * REPLY
|
||||||
|
* @typedef {string} MessageType
|
||||||
|
*/
|
||||||
|
export const MessageTypes = [
|
||||||
|
"DEFAULT",
|
||||||
|
"RECIPIENT_ADD",
|
||||||
|
"RECIPIENT_REMOVE",
|
||||||
|
"CALL",
|
||||||
|
"CHANNEL_NAME_CHANGE",
|
||||||
|
"CHANNEL_ICON_CHANGE",
|
||||||
|
"PINS_ADD",
|
||||||
|
"GUILD_MEMBER_JOIN",
|
||||||
|
"USER_PREMIUM_GUILD_SUBSCRIPTION",
|
||||||
|
"USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1",
|
||||||
|
"USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2",
|
||||||
|
"USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3",
|
||||||
|
"CHANNEL_FOLLOW_ADD",
|
||||||
|
null,
|
||||||
|
"GUILD_DISCOVERY_DISQUALIFIED",
|
||||||
|
"GUILD_DISCOVERY_REQUALIFIED",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
"REPLY",
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The types of messages that are `System`. The available types are `MessageTypes` excluding:
|
||||||
|
* * DEFAULT
|
||||||
|
* * REPLY
|
||||||
|
* @typedef {string} SystemMessageType
|
||||||
|
*/
|
||||||
|
export const SystemMessageTypes = MessageTypes.filter(
|
||||||
|
(type: string | null) => type && type !== "DEFAULT" && type !== "REPLY"
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <info>Bots cannot set a `CUSTOM_STATUS`, it is only for custom statuses received from users</info>
|
||||||
|
* The type of an activity of a users presence, e.g. `PLAYING`. Here are the available types:
|
||||||
|
* * PLAYING
|
||||||
|
* * STREAMING
|
||||||
|
* * LISTENING
|
||||||
|
* * WATCHING
|
||||||
|
* * CUSTOM_STATUS
|
||||||
|
* * COMPETING
|
||||||
|
* @typedef {string} ActivityType
|
||||||
|
*/
|
||||||
|
export const ActivityTypes = ["PLAYING", "STREAMING", "LISTENING", "WATCHING", "CUSTOM_STATUS", "COMPETING"];
|
||||||
|
|
||||||
|
export const ChannelTypes = {
|
||||||
|
TEXT: 0,
|
||||||
|
DM: 1,
|
||||||
|
VOICE: 2,
|
||||||
|
GROUP: 3,
|
||||||
|
CATEGORY: 4,
|
||||||
|
NEWS: 5,
|
||||||
|
STORE: 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ClientApplicationAssetTypes = {
|
||||||
|
SMALL: 1,
|
||||||
|
BIG: 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Colors = {
|
||||||
|
DEFAULT: 0x000000,
|
||||||
|
WHITE: 0xffffff,
|
||||||
|
AQUA: 0x1abc9c,
|
||||||
|
GREEN: 0x2ecc71,
|
||||||
|
BLUE: 0x3498db,
|
||||||
|
YELLOW: 0xffff00,
|
||||||
|
PURPLE: 0x9b59b6,
|
||||||
|
LUMINOUS_VIVID_PINK: 0xe91e63,
|
||||||
|
GOLD: 0xf1c40f,
|
||||||
|
ORANGE: 0xe67e22,
|
||||||
|
RED: 0xe74c3c,
|
||||||
|
GREY: 0x95a5a6,
|
||||||
|
NAVY: 0x34495e,
|
||||||
|
DARK_AQUA: 0x11806a,
|
||||||
|
DARK_GREEN: 0x1f8b4c,
|
||||||
|
DARK_BLUE: 0x206694,
|
||||||
|
DARK_PURPLE: 0x71368a,
|
||||||
|
DARK_VIVID_PINK: 0xad1457,
|
||||||
|
DARK_GOLD: 0xc27c0e,
|
||||||
|
DARK_ORANGE: 0xa84300,
|
||||||
|
DARK_RED: 0x992d22,
|
||||||
|
DARK_GREY: 0x979c9f,
|
||||||
|
DARKER_GREY: 0x7f8c8d,
|
||||||
|
LIGHT_GREY: 0xbcc0c0,
|
||||||
|
DARK_NAVY: 0x2c3e50,
|
||||||
|
BLURPLE: 0x7289da,
|
||||||
|
GREYPLE: 0x99aab5,
|
||||||
|
DARK_BUT_NOT_BLACK: 0x2c2f33,
|
||||||
|
NOT_QUITE_BLACK: 0x23272a,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value set for the explicit content filter levels for a guild:
|
||||||
|
* * DISABLED
|
||||||
|
* * MEMBERS_WITHOUT_ROLES
|
||||||
|
* * ALL_MEMBERS
|
||||||
|
* @typedef {string} ExplicitContentFilterLevel
|
||||||
|
*/
|
||||||
|
export const ExplicitContentFilterLevels = ["DISABLED", "MEMBERS_WITHOUT_ROLES", "ALL_MEMBERS"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value set for the verification levels for a guild:
|
||||||
|
* * NONE
|
||||||
|
* * LOW
|
||||||
|
* * MEDIUM
|
||||||
|
* * HIGH
|
||||||
|
* * VERY_HIGH
|
||||||
|
* @typedef {string} VerificationLevel
|
||||||
|
*/
|
||||||
|
export const VerificationLevels = ["NONE", "LOW", "MEDIUM", "HIGH", "VERY_HIGH"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An error encountered while performing an API request. Here are the potential errors:
|
||||||
|
* * UNKNOWN_ACCOUNT
|
||||||
|
* * UNKNOWN_APPLICATION
|
||||||
|
* * UNKNOWN_CHANNEL
|
||||||
|
* * UNKNOWN_GUILD
|
||||||
|
* * UNKNOWN_INTEGRATION
|
||||||
|
* * UNKNOWN_INVITE
|
||||||
|
* * UNKNOWN_MEMBER
|
||||||
|
* * UNKNOWN_MESSAGE
|
||||||
|
* * UNKNOWN_OVERWRITE
|
||||||
|
* * UNKNOWN_PROVIDER
|
||||||
|
* * UNKNOWN_ROLE
|
||||||
|
* * UNKNOWN_TOKEN
|
||||||
|
* * UNKNOWN_USER
|
||||||
|
* * UNKNOWN_EMOJI
|
||||||
|
* * UNKNOWN_WEBHOOK
|
||||||
|
* * UNKNOWN_BAN
|
||||||
|
* * UNKNOWN_GUILD_TEMPLATE
|
||||||
|
* * BOT_PROHIBITED_ENDPOINT
|
||||||
|
* * BOT_ONLY_ENDPOINT
|
||||||
|
* * CHANNEL_HIT_WRITE_RATELIMIT
|
||||||
|
* * MAXIMUM_GUILDS
|
||||||
|
* * MAXIMUM_FRIENDS
|
||||||
|
* * MAXIMUM_PINS
|
||||||
|
* * MAXIMUM_ROLES
|
||||||
|
* * MAXIMUM_WEBHOOKS
|
||||||
|
* * MAXIMUM_REACTIONS
|
||||||
|
* * MAXIMUM_CHANNELS
|
||||||
|
* * MAXIMUM_ATTACHMENTS
|
||||||
|
* * MAXIMUM_INVITES
|
||||||
|
* * GUILD_ALREADY_HAS_TEMPLATE
|
||||||
|
* * UNAUTHORIZED
|
||||||
|
* * ACCOUNT_VERIFICATION_REQUIRED
|
||||||
|
* * REQUEST_ENTITY_TOO_LARGE
|
||||||
|
* * FEATURE_TEMPORARILY_DISABLED
|
||||||
|
* * USER_BANNED
|
||||||
|
* * ALREADY_CROSSPOSTED
|
||||||
|
* * MISSING_ACCESS
|
||||||
|
* * INVALID_ACCOUNT_TYPE
|
||||||
|
* * CANNOT_EXECUTE_ON_DM
|
||||||
|
* * EMBED_DISABLED
|
||||||
|
* * CANNOT_EDIT_MESSAGE_BY_OTHER
|
||||||
|
* * CANNOT_SEND_EMPTY_MESSAGE
|
||||||
|
* * CANNOT_MESSAGE_USER
|
||||||
|
* * CANNOT_SEND_MESSAGES_IN_VOICE_CHANNEL
|
||||||
|
* * CHANNEL_VERIFICATION_LEVEL_TOO_HIGH
|
||||||
|
* * OAUTH2_APPLICATION_BOT_ABSENT
|
||||||
|
* * MAXIMUM_OAUTH2_APPLICATIONS
|
||||||
|
* * INVALID_OAUTH_STATE
|
||||||
|
* * MISSING_PERMISSIONS
|
||||||
|
* * INVALID_AUTHENTICATION_TOKEN
|
||||||
|
* * NOTE_TOO_LONG
|
||||||
|
* * INVALID_BULK_DELETE_QUANTITY
|
||||||
|
* * CANNOT_PIN_MESSAGE_IN_OTHER_CHANNEL
|
||||||
|
* * INVALID_OR_TAKEN_INVITE_CODE
|
||||||
|
* * CANNOT_EXECUTE_ON_SYSTEM_MESSAGE
|
||||||
|
* * INVALID_OAUTH_TOKEN
|
||||||
|
* * BULK_DELETE_MESSAGE_TOO_OLD
|
||||||
|
* * INVALID_FORM_BODY
|
||||||
|
* * INVITE_ACCEPTED_TO_GUILD_NOT_CONTAINING_BOT
|
||||||
|
* * INVALID_API_VERSION
|
||||||
|
* * CANNOT_DELETE_COMMUNITY_REQUIRED_CHANNEL
|
||||||
|
* * REACTION_BLOCKED
|
||||||
|
* * RESOURCE_OVERLOADED
|
||||||
|
* @typedef {string} APIError
|
||||||
|
*/
|
||||||
|
export const APIErrors = {
|
||||||
|
UNKNOWN_ACCOUNT: 10001,
|
||||||
|
UNKNOWN_APPLICATION: 10002,
|
||||||
|
UNKNOWN_CHANNEL: 10003,
|
||||||
|
UNKNOWN_GUILD: 10004,
|
||||||
|
UNKNOWN_INTEGRATION: 10005,
|
||||||
|
UNKNOWN_INVITE: 10006,
|
||||||
|
UNKNOWN_MEMBER: 10007,
|
||||||
|
UNKNOWN_MESSAGE: 10008,
|
||||||
|
UNKNOWN_OVERWRITE: 10009,
|
||||||
|
UNKNOWN_PROVIDER: 10010,
|
||||||
|
UNKNOWN_ROLE: 10011,
|
||||||
|
UNKNOWN_TOKEN: 10012,
|
||||||
|
UNKNOWN_USER: 10013,
|
||||||
|
UNKNOWN_EMOJI: 10014,
|
||||||
|
UNKNOWN_WEBHOOK: 10015,
|
||||||
|
UNKNOWN_BAN: 10026,
|
||||||
|
UNKNOWN_GUILD_TEMPLATE: 10057,
|
||||||
|
BOT_PROHIBITED_ENDPOINT: 20001,
|
||||||
|
BOT_ONLY_ENDPOINT: 20002,
|
||||||
|
CHANNEL_HIT_WRITE_RATELIMIT: 20028,
|
||||||
|
MAXIMUM_GUILDS: 30001,
|
||||||
|
MAXIMUM_FRIENDS: 30002,
|
||||||
|
MAXIMUM_PINS: 30003,
|
||||||
|
MAXIMUM_ROLES: 30005,
|
||||||
|
MAXIMUM_WEBHOOKS: 30007,
|
||||||
|
MAXIMUM_REACTIONS: 30010,
|
||||||
|
MAXIMUM_CHANNELS: 30013,
|
||||||
|
MAXIMUM_ATTACHMENTS: 30015,
|
||||||
|
MAXIMUM_INVITES: 30016,
|
||||||
|
GUILD_ALREADY_HAS_TEMPLATE: 30031,
|
||||||
|
UNAUTHORIZED: 40001,
|
||||||
|
ACCOUNT_VERIFICATION_REQUIRED: 40002,
|
||||||
|
REQUEST_ENTITY_TOO_LARGE: 40005,
|
||||||
|
FEATURE_TEMPORARILY_DISABLED: 40006,
|
||||||
|
USER_BANNED: 40007,
|
||||||
|
ALREADY_CROSSPOSTED: 40033,
|
||||||
|
MISSING_ACCESS: 50001,
|
||||||
|
INVALID_ACCOUNT_TYPE: 50002,
|
||||||
|
CANNOT_EXECUTE_ON_DM: 50003,
|
||||||
|
EMBED_DISABLED: 50004,
|
||||||
|
CANNOT_EDIT_MESSAGE_BY_OTHER: 50005,
|
||||||
|
CANNOT_SEND_EMPTY_MESSAGE: 50006,
|
||||||
|
CANNOT_MESSAGE_USER: 50007,
|
||||||
|
CANNOT_SEND_MESSAGES_IN_VOICE_CHANNEL: 50008,
|
||||||
|
CHANNEL_VERIFICATION_LEVEL_TOO_HIGH: 50009,
|
||||||
|
OAUTH2_APPLICATION_BOT_ABSENT: 50010,
|
||||||
|
MAXIMUM_OAUTH2_APPLICATIONS: 50011,
|
||||||
|
INVALID_OAUTH_STATE: 50012,
|
||||||
|
MISSING_PERMISSIONS: 50013,
|
||||||
|
INVALID_AUTHENTICATION_TOKEN: 50014,
|
||||||
|
NOTE_TOO_LONG: 50015,
|
||||||
|
INVALID_BULK_DELETE_QUANTITY: 50016,
|
||||||
|
CANNOT_PIN_MESSAGE_IN_OTHER_CHANNEL: 50019,
|
||||||
|
INVALID_OR_TAKEN_INVITE_CODE: 50020,
|
||||||
|
CANNOT_EXECUTE_ON_SYSTEM_MESSAGE: 50021,
|
||||||
|
INVALID_OAUTH_TOKEN: 50025,
|
||||||
|
BULK_DELETE_MESSAGE_TOO_OLD: 50034,
|
||||||
|
INVALID_FORM_BODY: 50035,
|
||||||
|
INVITE_ACCEPTED_TO_GUILD_NOT_CONTAINING_BOT: 50036,
|
||||||
|
INVALID_API_VERSION: 50041,
|
||||||
|
CANNOT_DELETE_COMMUNITY_REQUIRED_CHANNEL: 50074,
|
||||||
|
REACTION_BLOCKED: 90001,
|
||||||
|
RESOURCE_OVERLOADED: 130000,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value set for a guild's default message notifications, e.g. `ALL`. Here are the available types:
|
||||||
|
* * ALL
|
||||||
|
* * MENTIONS
|
||||||
|
* @typedef {string} DefaultMessageNotifications
|
||||||
|
*/
|
||||||
|
export const DefaultMessageNotifications = ["ALL", "MENTIONS"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value set for a team members's membership state:
|
||||||
|
* * INVITED
|
||||||
|
* * ACCEPTED
|
||||||
|
* @typedef {string} MembershipStates
|
||||||
|
*/
|
||||||
|
export const MembershipStates = [
|
||||||
|
// They start at 1
|
||||||
|
null,
|
||||||
|
"INVITED",
|
||||||
|
"ACCEPTED",
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value set for a webhook's type:
|
||||||
|
* * Incoming
|
||||||
|
* * Channel Follower
|
||||||
|
* @typedef {string} WebhookTypes
|
||||||
|
*/
|
||||||
|
export const WebhookTypes = [
|
||||||
|
// They start at 1
|
||||||
|
null,
|
||||||
|
"Incoming",
|
||||||
|
"Channel Follower",
|
||||||
|
];
|
||||||
|
|
||||||
|
function keyMirror(arr: string[]) {
|
||||||
|
let tmp = Object.create(null);
|
||||||
|
for (const value of arr) tmp[value] = value;
|
||||||
|
return tmp;
|
||||||
|
}
|
14
src/util/MessageFlags.ts
Normal file
14
src/util/MessageFlags.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// https://github.com/discordjs/discord.js/blob/master/src/util/MessageFlags.js
|
||||||
|
// Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah
|
||||||
|
|
||||||
|
import { BitField } from "./BitField";
|
||||||
|
|
||||||
|
export class MessageFlags extends BitField {
|
||||||
|
static FLAGS = {
|
||||||
|
CROSSPOSTED: 1 << 0,
|
||||||
|
IS_CROSSPOST: 1 << 1,
|
||||||
|
SUPPRESS_EMBEDS: 1 << 2,
|
||||||
|
SOURCE_MESSAGE_DELETED: 1 << 3,
|
||||||
|
URGENT: 1 << 4,
|
||||||
|
};
|
||||||
|
}
|
56
src/util/Permissions.ts
Normal file
56
src/util/Permissions.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// https://github.com/discordjs/discord.js/blob/master/src/util/Permissions.js
|
||||||
|
// Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah
|
||||||
|
|
||||||
|
import { BitField } from "./BitField";
|
||||||
|
|
||||||
|
export type PermissionResolvable = string | number | Permissions | PermissionResolvable[];
|
||||||
|
|
||||||
|
export class Permissions extends BitField {
|
||||||
|
static FLAGS = {
|
||||||
|
CREATE_INSTANT_INVITE: 1 << 0,
|
||||||
|
KICK_MEMBERS: 1 << 1,
|
||||||
|
BAN_MEMBERS: 1 << 2,
|
||||||
|
ADMINISTRATOR: 1 << 3,
|
||||||
|
MANAGE_CHANNELS: 1 << 4,
|
||||||
|
MANAGE_GUILD: 1 << 5,
|
||||||
|
ADD_REACTIONS: 1 << 6,
|
||||||
|
VIEW_AUDIT_LOG: 1 << 7,
|
||||||
|
PRIORITY_SPEAKER: 1 << 8,
|
||||||
|
STREAM: 1 << 9,
|
||||||
|
VIEW_CHANNEL: 1 << 10,
|
||||||
|
SEND_MESSAGES: 1 << 11,
|
||||||
|
SEND_TTS_MESSAGES: 1 << 12,
|
||||||
|
MANAGE_MESSAGES: 1 << 13,
|
||||||
|
EMBED_LINKS: 1 << 14,
|
||||||
|
ATTACH_FILES: 1 << 15,
|
||||||
|
READ_MESSAGE_HISTORY: 1 << 16,
|
||||||
|
MENTION_EVERYONE: 1 << 17,
|
||||||
|
USE_EXTERNAL_EMOJIS: 1 << 18,
|
||||||
|
VIEW_GUILD_INSIGHTS: 1 << 19,
|
||||||
|
CONNECT: 1 << 20,
|
||||||
|
SPEAK: 1 << 21,
|
||||||
|
MUTE_MEMBERS: 1 << 22,
|
||||||
|
DEAFEN_MEMBERS: 1 << 23,
|
||||||
|
MOVE_MEMBERS: 1 << 24,
|
||||||
|
USE_VAD: 1 << 25,
|
||||||
|
CHANGE_NICKNAME: 1 << 26,
|
||||||
|
MANAGE_NICKNAMES: 1 << 27,
|
||||||
|
MANAGE_ROLES: 1 << 28,
|
||||||
|
MANAGE_WEBHOOKS: 1 << 29,
|
||||||
|
MANAGE_EMOJIS: 1 << 30,
|
||||||
|
};
|
||||||
|
|
||||||
|
any(permission: PermissionResolvable, checkAdmin = true) {
|
||||||
|
return (checkAdmin && super.has(Permissions.FLAGS.ADMINISTRATOR)) || super.any(permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the bitfield has a permission, or multiple permissions.
|
||||||
|
* @param {PermissionResolvable} permission Permission(s) to check for
|
||||||
|
* @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
has(permission: PermissionResolvable, checkAdmin = true) {
|
||||||
|
return (checkAdmin && super.has(Permissions.FLAGS.ADMINISTRATOR)) || super.has(permission);
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,20 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
|
|
||||||
// github.com/discordjs/discord.js/blob/master/src/util/Snowflake.js
|
// https://github.com/discordjs/discord.js/blob/master/src/util/Snowflake.js
|
||||||
|
// Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// Discord epoch (2015-01-01T00:00:00.000Z)
|
// Discord epoch (2015-01-01T00:00:00.000Z)
|
||||||
const EPOCH = 1420070400000;
|
|
||||||
let INCREMENT = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A container for useful snowflake-related methods.
|
* A container for useful snowflake-related methods.
|
||||||
*/
|
*/
|
||||||
class SnowflakeUtil {
|
export class Snowflake {
|
||||||
|
static EPOCH = 1420070400000;
|
||||||
|
static INCREMENT = 0;
|
||||||
|
static processId = 0;
|
||||||
|
static workerId = 0;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
throw new Error(`The ${this.constructor.name} class may not be instantiated.`);
|
throw new Error(`The ${this.constructor.name} class may not be instantiated.`);
|
||||||
}
|
}
|
||||||
@ -91,11 +95,14 @@ class SnowflakeUtil {
|
|||||||
`"timestamp" argument must be a number (received ${isNaN(timestamp) ? "NaN" : typeof timestamp})`
|
`"timestamp" argument must be a number (received ${isNaN(timestamp) ? "NaN" : typeof timestamp})`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (INCREMENT >= 4095) INCREMENT = 0;
|
if (Snowflake.INCREMENT >= 4095) Snowflake.INCREMENT = 0;
|
||||||
const BINARY = `${(timestamp - EPOCH).toString(2).padStart(42, "0")}0000100000${(INCREMENT++)
|
let workerBin = Snowflake.workerId.toString(2).padStart(5, "0");
|
||||||
|
let processBin = Snowflake.processId.toString(2).padStart(5, "0");
|
||||||
|
|
||||||
|
const BINARY = `${(timestamp - EPOCH)
|
||||||
.toString(2)
|
.toString(2)
|
||||||
.padStart(12, "0")}`;
|
.padStart(42, "0")}${workerBin}${processBin}${(Snowflake.INCREMENT++).toString(2).padStart(12, "0")}`;
|
||||||
return SnowflakeUtil.binaryToID(BINARY);
|
return Snowflake.binaryToID(BINARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -115,7 +122,7 @@ class SnowflakeUtil {
|
|||||||
* @returns {DeconstructedSnowflake} Deconstructed snowflake
|
* @returns {DeconstructedSnowflake} Deconstructed snowflake
|
||||||
*/
|
*/
|
||||||
static deconstruct(snowflake) {
|
static deconstruct(snowflake) {
|
||||||
const BINARY = SnowflakeUtil.idToBinary(snowflake).toString(2).padStart(64, "0");
|
const BINARY = Snowflake.idToBinary(snowflake).toString(2).padStart(64, "0");
|
||||||
const res = {
|
const res = {
|
||||||
timestamp: parseInt(BINARY.substring(0, 42), 2) + EPOCH,
|
timestamp: parseInt(BINARY.substring(0, 42), 2) + EPOCH,
|
||||||
workerID: parseInt(BINARY.substring(42, 47), 2),
|
workerID: parseInt(BINARY.substring(42, 47), 2),
|
||||||
@ -141,5 +148,3 @@ class SnowflakeUtil {
|
|||||||
return EPOCH;
|
return EPOCH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = SnowflakeUtil;
|
|
22
src/util/UserFlags.ts
Normal file
22
src/util/UserFlags.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// https://github.com/discordjs/discord.js/blob/master/src/util/UserFlags.js
|
||||||
|
// Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah
|
||||||
|
|
||||||
|
import { BitField } from "./BitField";
|
||||||
|
|
||||||
|
export class UserFlags extends BitField {
|
||||||
|
static FLAGS = {
|
||||||
|
DISCORD_EMPLOYEE: 1 << 0,
|
||||||
|
PARTNERED_SERVER_OWNER: 1 << 1,
|
||||||
|
HYPESQUAD_EVENTS: 1 << 2,
|
||||||
|
BUGHUNTER_LEVEL_1: 1 << 3,
|
||||||
|
HOUSE_BRAVERY: 1 << 6,
|
||||||
|
HOUSE_BRILLIANCE: 1 << 7,
|
||||||
|
HOUSE_BALANCE: 1 << 8,
|
||||||
|
EARLY_SUPPORTER: 1 << 9,
|
||||||
|
TEAM_USER: 1 << 10,
|
||||||
|
SYSTEM: 1 << 12,
|
||||||
|
BUGHUNTER_LEVEL_2: 1 << 14,
|
||||||
|
VERIFIED_BOT: 1 << 16,
|
||||||
|
EARLY_VERIFIED_BOT_DEVELOPER: 1 << 17,
|
||||||
|
};
|
||||||
|
}
|
121
src/util/instanceOf.ts
Normal file
121
src/util/instanceOf.ts
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
// different version of lambert-server instanceOf with discord error format
|
||||||
|
|
||||||
|
import { NextFunction, Request, Response } from "express";
|
||||||
|
import { Tuple } from "lambert-server";
|
||||||
|
|
||||||
|
const OPTIONAL_PREFIX = "$";
|
||||||
|
|
||||||
|
export function check(schema: any) {
|
||||||
|
return (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
try {
|
||||||
|
const result = instanceOf(schema, req.body, { path: "body" });
|
||||||
|
if (result === true) return next();
|
||||||
|
throw result;
|
||||||
|
} catch (error) {
|
||||||
|
return res.status(400).json({ code: 50035, message: "Invalid Form Body", success: false, errors: error });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class FieldError extends Error {
|
||||||
|
constructor(public code: string, public message: string) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function instanceOf(
|
||||||
|
type: any,
|
||||||
|
value: any,
|
||||||
|
{ path = "", optional = false, errors = {} }: { path?: string; optional?: boolean; errors?: any } = {}
|
||||||
|
): Boolean {
|
||||||
|
try {
|
||||||
|
if (!type) return true; // no type was specified
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
if (optional) return true;
|
||||||
|
throw new FieldError("BASE_TYPE_REQUIRED", `This field is required`);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case String:
|
||||||
|
if (typeof value === "string") return true;
|
||||||
|
throw new FieldError("BASE_TYPE_STRING", `This field must be a string`);
|
||||||
|
case Number:
|
||||||
|
value = Number(value);
|
||||||
|
if (typeof value === "number" && !isNaN(value)) return true;
|
||||||
|
throw new FieldError("BASE_TYPE_NUMBER", `This field must be a number`);
|
||||||
|
case BigInt:
|
||||||
|
try {
|
||||||
|
value = BigInt(value);
|
||||||
|
if (typeof value === "bigint") return true;
|
||||||
|
} catch (error) {}
|
||||||
|
throw new FieldError("BASE_TYPE_BIGINT", `This field must be a bigint`);
|
||||||
|
case Boolean:
|
||||||
|
if (value == "true") value = true;
|
||||||
|
if (value == "false") value = false;
|
||||||
|
if (typeof value === "boolean") return true;
|
||||||
|
throw new FieldError("BASE_TYPE_BOOLEAN", `This field must be a boolean`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof type === "object") {
|
||||||
|
if (type?.constructor?.name != "Object") {
|
||||||
|
if (type instanceof Tuple) {
|
||||||
|
if ((<Tuple>type).types.some((x) => instanceOf(x, value, { path, optional, errors }))) return true;
|
||||||
|
throw new FieldError("BASE_TYPE_CHOICES", `This field must be one of (${type.types})`);
|
||||||
|
}
|
||||||
|
if (value instanceof type) return true;
|
||||||
|
throw new FieldError("BASE_TYPE_CLASS", `This field must be an instance of ${type}`);
|
||||||
|
}
|
||||||
|
if (typeof value !== "object") throw new FieldError("BASE_TYPE_OBJECT", `This field must be a object`);
|
||||||
|
|
||||||
|
if (Array.isArray(type)) {
|
||||||
|
if (!Array.isArray(value)) throw new FieldError("BASE_TYPE_ARRAY", `This field must be an array`);
|
||||||
|
if (!type.length) return true; // type array didn't specify any type
|
||||||
|
|
||||||
|
return (
|
||||||
|
value.every((val, i) => {
|
||||||
|
errors[i] = {};
|
||||||
|
return (
|
||||||
|
instanceOf(type[0], val, { path: `${path}[${i}]`, optional, errors: errors[i] }) === true
|
||||||
|
);
|
||||||
|
}) || errors
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const diff = Object.keys(value).missing(
|
||||||
|
Object.keys(type).map((x) => (x.startsWith(OPTIONAL_PREFIX) ? x.slice(OPTIONAL_PREFIX.length) : x))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (diff.length) throw new FieldError("UNKOWN_FIELD", `Unkown key ${diff}`);
|
||||||
|
|
||||||
|
return (
|
||||||
|
Object.keys(type).every((key) => {
|
||||||
|
let newKey = key;
|
||||||
|
const OPTIONAL = key.startsWith(OPTIONAL_PREFIX);
|
||||||
|
if (OPTIONAL) newKey = newKey.slice(OPTIONAL_PREFIX.length);
|
||||||
|
errors[key] = {};
|
||||||
|
|
||||||
|
return (
|
||||||
|
instanceOf(type[key], value[newKey], {
|
||||||
|
path: `${path}.${newKey}`,
|
||||||
|
optional: OPTIONAL,
|
||||||
|
errors: errors[key],
|
||||||
|
}) === true
|
||||||
|
);
|
||||||
|
}) || errors
|
||||||
|
);
|
||||||
|
} else if (typeof type === "number" || typeof type === "string" || typeof type === "boolean") {
|
||||||
|
if (value === type) return true;
|
||||||
|
throw new FieldError("BASE_TYPE_CONSTANT", `This field must be ${value}`);
|
||||||
|
} else if (typeof type === "bigint") {
|
||||||
|
if (BigInt(value) === type) return true;
|
||||||
|
throw new FieldError("BASE_TYPE_CONSTANT", `This field must be ${value}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return type == value;
|
||||||
|
} catch (error) {
|
||||||
|
let e = error as FieldError;
|
||||||
|
errors._errors = [{ message: e.message, code: e.code }];
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
}
|
@ -4,14 +4,14 @@
|
|||||||
|
|
||||||
/* Basic Options */
|
/* Basic Options */
|
||||||
// "incremental": true, /* Enable incremental compilation */
|
// "incremental": true, /* Enable incremental compilation */
|
||||||
"target": "ES6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
|
"target": "ES2020" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
|
||||||
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
|
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
|
||||||
"lib": ["ES2015", "DOM"] /* Specify library files to be included in the compilation. */,
|
"lib": ["ES2020"] /* Specify library files to be included in the compilation. */,
|
||||||
"allowJs": true /* Allow javascript files to be compiled. */,
|
"allowJs": true /* Allow javascript files to be compiled. */,
|
||||||
"checkJs": true /* Report errors in .js files. */,
|
"checkJs": true /* Report errors in .js files. */,
|
||||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||||
"declaration": true /* Generates corresponding '.d.ts' file. */,
|
"declaration": true /* Generates corresponding '.d.ts' file. */,
|
||||||
"declarationMap": true /* Generates a sourcemap for each corresponding '.d.ts' file. */,
|
"declarationMap": false /* Generates a sourcemap for each corresponding '.d.ts' file. */,
|
||||||
"sourceMap": true /* Generates corresponding '.map' file. */,
|
"sourceMap": true /* Generates corresponding '.map' file. */,
|
||||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||||
"outDir": "./dist/" /* Redirect output structure to the directory. */,
|
"outDir": "./dist/" /* Redirect output structure to the directory. */,
|
||||||
@ -27,7 +27,7 @@
|
|||||||
/* Strict Type-Checking Options */
|
/* Strict Type-Checking Options */
|
||||||
"strict": true /* Enable all strict type-checking options. */,
|
"strict": true /* Enable all strict type-checking options. */,
|
||||||
"noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
|
"noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
|
||||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
"strictNullChecks": true /* Enable strict null checks. */,
|
||||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||||
"strictPropertyInitialization": false /* Enable strict checking of property initialization in classes. */,
|
"strictPropertyInitialization": false /* Enable strict checking of property initialization in classes. */,
|
||||||
|
Loading…
Reference in New Issue
Block a user