mirror of
https://github.com/spacebarchat/server.git
synced 2024-09-19 17:21:35 +02:00
Merge branch 'master' into pr/darkhpp/261-2
This commit is contained in:
commit
ebff2f4241
1
.docker/env
Normal file
1
.docker/env
Normal file
@ -0,0 +1 @@
|
||||
MONGO_URL=mongodb://db:27017/fosscord?readPreference=secondaryPreferred
|
@ -15,13 +15,13 @@ jobs:
|
||||
include:
|
||||
- os: windows
|
||||
build: npm run bundle:windows
|
||||
artifact: fosscord-api-windows.exe
|
||||
artifact: fosscord-server-windows.exe
|
||||
- os: macos
|
||||
build: npm run bundle:macos
|
||||
artifact: fosscord-api-macos.app.tgz
|
||||
artifact: fosscord-server-macos.app.tgz
|
||||
- os: ubuntu
|
||||
build: npm run bundle:linux
|
||||
artifact: fosscord-api-linux.tgz
|
||||
artifact: fosscord-server-linux.tgz
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@ -29,6 +29,8 @@ jobs:
|
||||
with:
|
||||
node-version: 14
|
||||
- run: npm install
|
||||
env:
|
||||
MONGOMS_VERSION: 4.4.3
|
||||
- run: npm run build
|
||||
- run: ${{ matrix.build }}
|
||||
- uses: actions/upload-artifact@v2
|
||||
@ -46,43 +48,52 @@ jobs:
|
||||
uses: Saionaro/extract-package-version@v1.0.6
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: fosscord-api-windows-${{ github.sha }}.exe
|
||||
name: fosscord-server-windows.exe
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: fosscord-api-macos-${{ github.sha }}.app.tgz
|
||||
name: fosscord-server-macos.app.tgz
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: fosscord-api-linux-${{ github.sha }}.tgz
|
||||
name: fosscord-server-linux.tgz
|
||||
- uses: actions/create-release@v1
|
||||
id: create-release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: v${{ steps.extract_version.outputs.version }}
|
||||
release_name: Release ${{ steps.extract_version.outputs.version }}
|
||||
release_name: Server v${{ steps.extract_version.outputs.version }}
|
||||
draft: false
|
||||
prerelease: true # TODO: change this to false
|
||||
body: >
|
||||
## Download
|
||||
|
||||
- [Windows](https://github.com/fosscord/fosscord-server/releases/download/v${{ steps.extract_version.outputs.version }}/fosscord-server-windows.exe)
|
||||
|
||||
- [MacOS](https://github.com/fosscord/fosscord-server/releases/download/v${{ steps.extract_version.outputs.version }}/fosscord-server-macos.app.tgz)
|
||||
|
||||
- [Linux](https://github.com/fosscord/fosscord-server/releases/download/v${{ steps.extract_version.outputs.version }}/fosscord-server-linux.tgz)
|
||||
|
||||
- uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create-release.outputs.upload_url }}
|
||||
asset_path: fosscord-api-windows-${{ github.sha }}.exe
|
||||
asset_name: fosscord-api-windows.exe
|
||||
asset_path: fosscord-server-windows.exe
|
||||
asset_name: fosscord-server-windows.exe
|
||||
asset_content_type: application/vnd.microsoft.portable-executable
|
||||
- uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create-release.outputs.upload_url }}
|
||||
asset_path: fosscord-api-macos-${{ github.sha }}.app.tgz
|
||||
asset_name: fosscord-api-macos.app.tgz
|
||||
asset_path: fosscord-server-macos.app.tgz
|
||||
asset_name: fosscord-server-macos.app.tgz
|
||||
asset_content_type: application/gzip
|
||||
- uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create-release.outputs.upload_url }}
|
||||
asset_path: fosscord-api-linux-${{ github.sha }}.tgz
|
||||
asset_name: fosscord-api-linux.tgz
|
||||
asset_path: fosscord-server-linux.tgz
|
||||
asset_name: fosscord-server-linux.tgz
|
||||
asset_content_type: application/gzip
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -1 +1,4 @@
|
||||
node_modules/
|
||||
.DS_STORE
|
||||
db/
|
||||
dist/
|
||||
node_modules
|
||||
|
17
.vscode/launch.json
vendored
17
.vscode/launch.json
vendored
@ -1,17 +0,0 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"sourceMaps": true,
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Launch Server",
|
||||
"program": "${workspaceFolder}/dist/index.js",
|
||||
"preLaunchTask": "tsc: build - tsconfig.json",
|
||||
"outFiles": ["${workspaceFolder}/dist/**/*.js"]
|
||||
}
|
||||
]
|
||||
}
|
20
api/.github/ISSUE_TEMPLATE/-feature--.md
vendored
20
api/.github/ISSUE_TEMPLATE/-feature--.md
vendored
@ -1,20 +0,0 @@
|
||||
---
|
||||
name: "[Feature] "
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
71
api/.github/workflows/codeql-analysis.yml
vendored
71
api/.github/workflows/codeql-analysis.yml
vendored
@ -1,71 +0,0 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '25 10 * * 5'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more:
|
||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
47
api/.github/workflows/docker-publish.yml
vendored
47
api/.github/workflows/docker-publish.yml
vendored
@ -1,47 +0,0 @@
|
||||
name: docker-publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
-
|
||||
name: Cache Docker layers
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ secrets.DOCKERHUB_TAGS }}
|
||||
cache-from: type=local,src=/tmp/.buildx-cache
|
||||
cache-to: type=local,dest=/tmp/.buildx-cache-new
|
||||
-
|
||||
# Hackfix to cleanup cache; replace after buildx 0.6 and BuildKit 0.9 are released
|
||||
# https://github.com/docker/build-push-action/pull/406#issuecomment-879184394
|
||||
name: Move cache fix
|
||||
run: |
|
||||
rm -rf /tmp/.buildx-cache
|
||||
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
|
27
api/package-lock.json
generated
27
api/package-lock.json
generated
@ -6,9 +6,10 @@
|
||||
"packages": {
|
||||
"": {
|
||||
"version": "1.0.0",
|
||||
"hasInstallScript": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@fosscord/server-util": "file:../util",
|
||||
"@fosscord/util": "file:../util",
|
||||
"@types/jest": "^26.0.22",
|
||||
"@types/json-schema": "^7.0.7",
|
||||
"ajv": "^8.4.0",
|
||||
@ -705,6 +706,10 @@
|
||||
"resolved": "../util",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@fosscord/util": {
|
||||
"resolved": "../util",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@istanbuljs/load-nyc-config": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
|
||||
@ -12031,6 +12036,26 @@
|
||||
"typescript": "^4.1.3"
|
||||
}
|
||||
},
|
||||
"@fosscord/util": {
|
||||
"version": "file:../util",
|
||||
"requires": {
|
||||
"@types/amqplib": "^0.8.1",
|
||||
"@types/jsonwebtoken": "^8.5.0",
|
||||
"@types/mongoose-autopopulate": "^0.10.1",
|
||||
"@types/mongoose-lean-virtuals": "^0.5.1",
|
||||
"@types/node": "^14.14.25",
|
||||
"ajv": "^8.5.0",
|
||||
"amqplib": "^0.8.0",
|
||||
"dot-prop": "^6.0.1",
|
||||
"env-paths": "^2.2.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"missing-native-js-functions": "^1.2.2",
|
||||
"mongodb": "^3.6.9",
|
||||
"mongoose": "^5.13.7",
|
||||
"mongoose-autopopulate": "^0.12.3",
|
||||
"typescript": "^4.1.3"
|
||||
}
|
||||
},
|
||||
"@istanbuljs/load-nyc-config": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
|
||||
|
@ -5,6 +5,8 @@
|
||||
"main": "dist/Server.js",
|
||||
"types": "dist/Server.d.ts",
|
||||
"scripts": {
|
||||
"link": "npm run build && npm link",
|
||||
"postinstall": "npm run --prefix ../util/ link && npm link @fosscord/util && npm run link",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"start": "npm run build && node dist/start",
|
||||
@ -33,7 +35,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/fosscord/fosscord-api#readme",
|
||||
"dependencies": {
|
||||
"@fosscord/server-util": "file:../util",
|
||||
"@fosscord/util": "file:../util",
|
||||
"@types/jest": "^26.0.22",
|
||||
"@types/json-schema": "^7.0.7",
|
||||
"ajv": "^8.4.0",
|
||||
|
@ -3,7 +3,7 @@ import fs from "fs";
|
||||
import { Connection } from "mongoose";
|
||||
import { Server, ServerOptions } from "lambert-server";
|
||||
import { Authentication, CORS } from "./middlewares/";
|
||||
import { Config, db, RabbitMQ } from "@fosscord/server-util";
|
||||
import { Config, db, initEvent, RabbitMQ } from "@fosscord/util";
|
||||
import i18next from "i18next";
|
||||
import i18nextMiddleware, { I18next } from "i18next-http-middleware";
|
||||
import i18nextBackend from "i18next-node-fs-backend";
|
||||
@ -56,9 +56,8 @@ export class FosscordServer extends Server {
|
||||
// @ts-ignore
|
||||
await (db as Promise<Connection>);
|
||||
await this.setupSchema();
|
||||
console.log("[Database] connected");
|
||||
await Config.init();
|
||||
await RabbitMQ.init();
|
||||
await initEvent();
|
||||
|
||||
this.app.use(CORS);
|
||||
this.app.use(Authentication);
|
||||
@ -93,11 +92,12 @@ export class FosscordServer extends Server {
|
||||
app.use("/api/v9", api);
|
||||
app.use("/api", api); // allow unversioned requests
|
||||
|
||||
api.get("*", (req: Request, res: Response) => {
|
||||
api.get("*", (req: Request, res: Response, next) => {
|
||||
res.status(404).json({
|
||||
message: "404: Not Found",
|
||||
code: 0
|
||||
});
|
||||
next();
|
||||
});
|
||||
|
||||
this.app = app;
|
||||
|
@ -7,9 +7,7 @@ export * from "./schema/Invite";
|
||||
export * from "./schema/Message";
|
||||
export * from "./util/Config";
|
||||
export * from "./util/Constants";
|
||||
export * from "./util/Event";
|
||||
export * from "./util/instanceOf";
|
||||
export * from "./util/Event";
|
||||
export * from "./util/instanceOf";
|
||||
export * from "./util/Member";
|
||||
export * from "./util/RandomInviteID";
|
||||
|
@ -1,15 +1,15 @@
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { checkToken, Config } from "@fosscord/server-util";
|
||||
import { checkToken, Config } from "@fosscord/util";
|
||||
|
||||
export const NO_AUTHORIZATION_ROUTES = [
|
||||
/^\/api(\/v\d+)?\/auth\/login/,
|
||||
/^\/api(\/v\d+)?\/auth\/register/,
|
||||
/^\/api(\/v\d+)?\/webhooks\//,
|
||||
/^\/api(\/v\d+)?\/ping/,
|
||||
/^\/api(\/v\d+)?\/gateway/,
|
||||
/^\/api(\/v\d+)?\/experiments/,
|
||||
/^\/api(\/v\d+)?\/guilds\/\d+\/widget\.(json|png)/
|
||||
"/auth/login",
|
||||
"/auth/register",
|
||||
"/webhooks/",
|
||||
"/ping",
|
||||
"/gateway",
|
||||
"/experiments"
|
||||
// /^\/api(\/v\d+)?\/guilds\/\d+\/widget\.(json|png)/
|
||||
];
|
||||
|
||||
export const API_PREFIX = /^\/api(\/v\d+)?/;
|
||||
@ -24,13 +24,14 @@ declare global {
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO wenn client offen ist, wird http://localhost:8080/api/v9/users/@me/guild-events blockiert?
|
||||
|
||||
export async function Authentication(req: Request, res: Response, next: NextFunction) {
|
||||
if (req.method === "OPTIONS") return res.sendStatus(204);
|
||||
if (!req.url.startsWith("/api")) return next();
|
||||
const apiPath = req.url.replace(API_PREFIX, "");
|
||||
if (apiPath.startsWith("/invites") && req.method === "GET") return next();
|
||||
if (NO_AUTHORIZATION_ROUTES.some((x) => x.test(req.url))) return next();
|
||||
if (apiPath.startsWith("/invites") && req.method === "GET") return next(); // @ts-ignore
|
||||
if (NO_AUTHORIZATION_ROUTES.some((x) => apiPath.startsWith(x) || x.test?.(req.url))) return next();
|
||||
if (!req.headers.authorization) return next(new HTTPError("Missing Authorization Header", 401));
|
||||
|
||||
try {
|
||||
|
@ -25,8 +25,6 @@ export function ErrorHandler(error: Error, req: Request, res: Response, next: Ne
|
||||
if (httpcode > 511) httpcode = 400;
|
||||
|
||||
res.status(httpcode).json({ code: code, message, errors });
|
||||
|
||||
return;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(500).json({ code: 500, message: "Internal Server Error" });
|
||||
|
@ -1,16 +1,17 @@
|
||||
import { db, MongooseCache, Bucket, Config } from "@fosscord/server-util";
|
||||
// @ts-nocheck
|
||||
import { db, Bucket, Config } from "@fosscord/util";
|
||||
import { NextFunction, Request, Response, Router } from "express";
|
||||
import { getIpAdress } from "../util/ipAddress";
|
||||
import { API_PREFIX_TRAILING_SLASH } from "./Authentication";
|
||||
|
||||
const Cache = new MongooseCache(
|
||||
db.collection("ratelimits"),
|
||||
[
|
||||
// TODO: uncomment $match and fix error: not receiving change events
|
||||
// { $match: { blocked: true } }
|
||||
],
|
||||
{ onlyEvents: false, array: true }
|
||||
);
|
||||
// const Cache = new MongooseCache(
|
||||
// db.collection("ratelimits"),
|
||||
// [
|
||||
// // TODO: uncomment $match and fix error: not receiving change events
|
||||
// // { $match: { blocked: true } }
|
||||
// ],
|
||||
// { onlyEvents: false, array: true }
|
||||
// );
|
||||
|
||||
// Docs: https://discord.com/developers/docs/topics/rate-limits
|
||||
|
||||
@ -31,6 +32,7 @@ TODO: use config values
|
||||
|
||||
*/
|
||||
|
||||
// TODO: FIX with new event handling
|
||||
export default function RateLimit(opts: {
|
||||
bucket?: string;
|
||||
window: number;
|
||||
@ -44,6 +46,7 @@ export default function RateLimit(opts: {
|
||||
success?: boolean;
|
||||
onlyIp?: boolean;
|
||||
}): any {
|
||||
return (req, res, next) => next();
|
||||
Cache.init(); // will only initalize it once
|
||||
|
||||
return async (req: Request, res: Response, next: NextFunction): Promise<any> => {
|
||||
|
@ -2,7 +2,7 @@ import { Request, Response, Router } from "express";
|
||||
import { check, FieldErrors, Length } from "../../util/instanceOf";
|
||||
import bcrypt from "bcrypt";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { Config, UserModel } from "@fosscord/server-util";
|
||||
import { Config, UserModel } from "@fosscord/util";
|
||||
import { adjustEmail } from "./register";
|
||||
import RateLimit from "../../middlewares/RateLimit";
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
import { trimSpecial, User, Snowflake, UserModel, Config } from "@fosscord/server-util";
|
||||
import { trimSpecial, User, Snowflake, UserModel, Config } from "@fosscord/util";
|
||||
import bcrypt from "bcrypt";
|
||||
import { check, Email, EMAIL_REGEX, FieldErrors, Length } from "../../util/instanceOf";
|
||||
import "missing-native-js-functions";
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { ChannelDeleteEvent, ChannelModel, ChannelUpdateEvent, getPermission, GuildUpdateEvent, toObject } from "@fosscord/server-util";
|
||||
import { ChannelDeleteEvent, ChannelModel, ChannelUpdateEvent, emitEvent, getPermission, GuildUpdateEvent, toObject } from "@fosscord/util";
|
||||
import { Router, Response, Request } from "express";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { ChannelModifySchema } from "../../../schema/Channel";
|
||||
import { emitEvent } from "../../../util/Event";
|
||||
import { check } from "../../../util/instanceOf";
|
||||
const router: Router = Router();
|
||||
// TODO: delete channel
|
||||
|
@ -3,11 +3,10 @@ import { HTTPError } from "lambert-server";
|
||||
|
||||
import { check } from "../../../util/instanceOf";
|
||||
import { random } from "../../../util/RandomInviteID";
|
||||
import { emitEvent } from "../../../util/Event";
|
||||
|
||||
import { InviteCreateSchema } from "../../../schema/Invite";
|
||||
|
||||
import { getPermission, ChannelModel, InviteModel, InviteCreateEvent, toObject } from "@fosscord/server-util";
|
||||
import { getPermission, ChannelModel, InviteModel, InviteCreateEvent, toObject, emitEvent } from "@fosscord/util";
|
||||
|
||||
const router: Router = Router();
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { getPermission, MessageAckEvent, ReadStateModel } from "@fosscord/server-util";
|
||||
import { emitEvent, getPermission, MessageAckEvent, ReadStateModel } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { emitEvent } from "../../../../../util/Event";
|
||||
|
||||
import { check } from "../../../../../util/instanceOf";
|
||||
|
||||
const router = Router();
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { ChannelModel, getPermission, MessageDeleteEvent, MessageModel, MessageUpdateEvent, toObject } from "@fosscord/server-util";
|
||||
import { ChannelModel, emitEvent, getPermission, MessageDeleteEvent, MessageModel, MessageUpdateEvent, toObject } from "@fosscord/util";
|
||||
import { Router, Response, Request } from "express";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { MessageCreateSchema } from "../../../../../schema/Message";
|
||||
import { emitEvent } from "../../../../../util/Event";
|
||||
|
||||
import { check } from "../../../../../util/instanceOf";
|
||||
import { handleMessage, postHandleMessage } from "../../../../../util/Message";
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import {
|
||||
ChannelModel,
|
||||
emitEvent,
|
||||
EmojiModel,
|
||||
getPermission,
|
||||
MemberModel,
|
||||
@ -12,10 +13,9 @@ import {
|
||||
PublicUserProjection,
|
||||
toObject,
|
||||
UserModel
|
||||
} from "@fosscord/server-util";
|
||||
} from "@fosscord/util";
|
||||
import { Router, Response, Request } from "express";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { emitEvent } from "../../../../../util/Event";
|
||||
|
||||
const router = Router();
|
||||
// TODO: check if emoji is really an unicode emoji or a prperly encoded external emoji
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import { ChannelModel, Config, getPermission, MessageDeleteBulkEvent, MessageModel } from "@fosscord/server-util";
|
||||
import { ChannelModel, Config, emitEvent, getPermission, MessageDeleteBulkEvent, MessageModel } from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { emitEvent } from "../../../../util/Event";
|
||||
|
||||
import { check } from "../../../../util/instanceOf";
|
||||
|
||||
const router: Router = Router();
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import { Attachment, ChannelModel, ChannelType, getPermission, MessageDocument, MessageModel, toObject } from "@fosscord/server-util";
|
||||
import { Attachment, ChannelModel, ChannelType, getPermission, MessageDocument, MessageModel, toObject } from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { MessageCreateSchema } from "../../../../schema/Message";
|
||||
import { check, instanceOf, Length } from "../../../../util/instanceOf";
|
||||
|
@ -1,7 +1,15 @@
|
||||
import { ChannelModel, ChannelPermissionOverwrite, ChannelUpdateEvent, getPermission, MemberModel, RoleModel } from "@fosscord/server-util";
|
||||
import {
|
||||
ChannelModel,
|
||||
ChannelPermissionOverwrite,
|
||||
ChannelUpdateEvent,
|
||||
emitEvent,
|
||||
getPermission,
|
||||
MemberModel,
|
||||
RoleModel
|
||||
} from "@fosscord/util";
|
||||
import { Router, Response, Request } from "express";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { emitEvent } from "../../../util/Event";
|
||||
|
||||
import { check } from "../../../util/instanceOf";
|
||||
const router: Router = Router();
|
||||
|
||||
|
@ -2,14 +2,14 @@ import {
|
||||
ChannelModel,
|
||||
ChannelPinsUpdateEvent,
|
||||
Config,
|
||||
emitEvent,
|
||||
getPermission,
|
||||
MessageModel,
|
||||
MessageUpdateEvent,
|
||||
toObject
|
||||
} from "@fosscord/server-util";
|
||||
} from "@fosscord/util";
|
||||
import { Router, Request, Response } from "express";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { emitEvent } from "../../../util/Event";
|
||||
|
||||
const router: Router = Router();
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { ChannelModel, MemberModel, toObject, TypingStartEvent } from "@fosscord/server-util";
|
||||
import { ChannelModel, emitEvent, MemberModel, toObject, TypingStartEvent } from "@fosscord/util";
|
||||
import { Router, Request, Response } from "express";
|
||||
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { emitEvent } from "../../../util/Event";
|
||||
|
||||
const router: Router = Router();
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import { check, Length } from "../../../util/instanceOf";
|
||||
import { ChannelModel, getPermission, trimSpecial } from "@fosscord/server-util";
|
||||
import { ChannelModel, getPermission, trimSpecial } from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { isTextChannel } from "./messages/index";
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Config } from "@fosscord/server-util";
|
||||
import { Config } from "@fosscord/util";
|
||||
import { Router, Response, Request } from "express";
|
||||
|
||||
const router = Router();
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
import { BanModel, getPermission, GuildBanAddEvent, GuildBanRemoveEvent, GuildModel, toObject } from "@fosscord/server-util";
|
||||
import { BanModel, emitEvent, getPermission, GuildBanAddEvent, GuildBanRemoveEvent, GuildModel, toObject } from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { getIpAdress } from "../../../util/ipAddress";
|
||||
import { BanCreateSchema } from "../../../schema/Ban";
|
||||
import { emitEvent } from "../../../util/Event";
|
||||
|
||||
import { check } from "../../../util/instanceOf";
|
||||
import { removeMember } from "../../../util/Member";
|
||||
import { getPublicUser } from "../../../util/User";
|
||||
|
@ -8,11 +8,12 @@ import {
|
||||
toObject,
|
||||
ChannelUpdateEvent,
|
||||
AnyChannel,
|
||||
getPermission
|
||||
} from "@fosscord/server-util";
|
||||
getPermission,
|
||||
emitEvent
|
||||
} from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { ChannelModifySchema } from "../../../schema/Channel";
|
||||
import { emitEvent } from "../../../util/Event";
|
||||
|
||||
import { check } from "../../../util/instanceOf";
|
||||
import { createChannel } from "../../../util/Channel";
|
||||
const router = Router();
|
||||
@ -64,7 +65,7 @@ router.patch(
|
||||
|
||||
const channel = await ChannelModel.findOneAndUpdate({ id: req.body, guild_id }, opts).exec();
|
||||
|
||||
await emitEvent({ event: "CHANNEL_UPDATE", data: channel, channel_id: body.id, guild_id } as ChannelUpdateEvent);
|
||||
await emitEvent({ event: "CHANNEL_UPDATE", data: toObject(channel), channel_id: body.id, guild_id } as ChannelUpdateEvent);
|
||||
|
||||
res.json(toObject(channel));
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import {
|
||||
ChannelModel,
|
||||
emitEvent,
|
||||
EmojiModel,
|
||||
GuildDeleteEvent,
|
||||
GuildModel,
|
||||
@ -8,10 +9,9 @@ import {
|
||||
MessageModel,
|
||||
RoleModel,
|
||||
UserModel
|
||||
} from "@fosscord/server-util";
|
||||
} from "@fosscord/util";
|
||||
import { Router, Request, Response } from "express";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { emitEvent } from "../../../util/Event";
|
||||
|
||||
const router = Router();
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
import {
|
||||
ChannelModel,
|
||||
emitEvent,
|
||||
EmojiModel,
|
||||
getPermission,
|
||||
GuildDeleteEvent,
|
||||
@ -12,10 +13,10 @@ import {
|
||||
RoleModel,
|
||||
toObject,
|
||||
UserModel
|
||||
} from "@fosscord/server-util";
|
||||
} from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { GuildUpdateSchema } from "../../../schema/Guild";
|
||||
import { emitEvent } from "../../../util/Event";
|
||||
|
||||
import { check } from "../../../util/instanceOf";
|
||||
import { handleFile } from "../../../util/cdn";
|
||||
import "missing-native-js-functions";
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getPermission, InviteModel, toObject } from "@fosscord/server-util";
|
||||
import { getPermission, InviteModel, toObject } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router = Router();
|
||||
|
@ -8,13 +8,13 @@ import {
|
||||
getPermission,
|
||||
PermissionResolvable,
|
||||
RoleModel,
|
||||
GuildMemberUpdateEvent
|
||||
} from "@fosscord/server-util";
|
||||
GuildMemberUpdateEvent,
|
||||
emitEvent
|
||||
} from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { addMember, isMember, removeMember } from "../../../../../util/Member";
|
||||
import { check } from "../../../../../util/instanceOf";
|
||||
import { MemberChangeSchema } from "../../../../../schema/Member";
|
||||
import { emitEvent } from "../../../../../util/Event";
|
||||
|
||||
const router = Router();
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getPermission, PermissionResolvable } from "@fosscord/server-util";
|
||||
import { getPermission, PermissionResolvable } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { check } from "lambert-server";
|
||||
import { MemberNickChangeSchema } from "../../../../../schema/Member";
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getPermission } from "@fosscord/server-util";
|
||||
import { getPermission } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { addRole, removeRole } from "../../../../../../../util/Member";
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
import { GuildModel, MemberModel, toObject } from "@fosscord/server-util";
|
||||
import { GuildModel, MemberModel, toObject } from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { instanceOf, Length } from "../../../../util/instanceOf";
|
||||
import { PublicMemberProjection, isMember } from "../../../../util/Member";
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Config } from "@fosscord/server-util";
|
||||
import { Config } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router = Router();
|
||||
|
@ -9,10 +9,11 @@ import {
|
||||
MemberModel,
|
||||
GuildRoleCreateEvent,
|
||||
GuildRoleUpdateEvent,
|
||||
GuildRoleDeleteEvent
|
||||
} from "@fosscord/server-util";
|
||||
GuildRoleDeleteEvent,
|
||||
emitEvent
|
||||
} from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { emitEvent } from "../../../util/Event";
|
||||
|
||||
import { check } from "../../../util/instanceOf";
|
||||
import { RoleModifySchema } from "../../../schema/Roles";
|
||||
import { getPublicUser } from "../../../util/User";
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
import { TemplateModel, GuildModel, getPermission, toObject, UserModel, Snowflake } from "@fosscord/server-util";
|
||||
import { TemplateModel, GuildModel, getPermission, toObject, UserModel, Snowflake } from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { TemplateCreateSchema, TemplateModifySchema } from "../../../schema/Template";
|
||||
import { check } from "../../../util/instanceOf";
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getPermission, GuildModel, InviteModel, trimSpecial } from "@fosscord/server-util";
|
||||
import { getPermission, GuildModel, InviteModel, trimSpecial } from "@fosscord/util";
|
||||
import { Router, Request, Response } from "express";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { check, Length } from "../../../util/instanceOf";
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
import { GuildModel, getPermission, toObject, Snowflake } from "@fosscord/server-util";
|
||||
import { GuildModel, getPermission, toObject, Snowflake } from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { emitEvent } from "../../../util/Event";
|
||||
|
||||
import { check } from "../../../util/instanceOf";
|
||||
import { isMember } from "../../../util/Member";
|
||||
import { GuildAddChannelToWelcomeScreenSchema } from "../../../schema/Guild";
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
import { Config, Permissions, GuildModel, InviteModel, ChannelModel, MemberModel } from "@fosscord/server-util";
|
||||
import { Config, Permissions, GuildModel, InviteModel, ChannelModel, MemberModel } from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { random } from "../../../util/RandomInviteID";
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
import { GuildModel } from "@fosscord/server-util";
|
||||
import { GuildModel } from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
import { getPermission, GuildModel } from "@fosscord/server-util";
|
||||
import { getPermission, GuildModel } from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { check } from "../../../util/instanceOf";
|
||||
import { WidgetModifySchema } from "../../../schema/Widget";
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Router, Request, Response } from "express";
|
||||
import { RoleModel, GuildModel, Snowflake, Guild, RoleDocument, Config } from "@fosscord/server-util";
|
||||
import { RoleModel, GuildModel, Snowflake, Guild, RoleDocument, Config } from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { check } from "./../../util/instanceOf";
|
||||
import { GuildCreateSchema } from "../../schema/Guild";
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
const router: Router = Router();
|
||||
import { TemplateModel, GuildModel, toObject, UserModel, RoleModel, Snowflake, Guild, Config } from "@fosscord/server-util";
|
||||
import { TemplateModel, GuildModel, toObject, UserModel, RoleModel, Snowflake, Guild, Config } from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { GuildTemplateCreateSchema } from "../../../schema/Guild";
|
||||
import { getPublicUser } from "../../../util/User";
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Router, Request, Response } from "express";
|
||||
import { getPermission, InviteModel, toObject } from "@fosscord/server-util";
|
||||
import { getPermission, InviteModel, toObject } from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { addMember } from "../../util/Member";
|
||||
const router: Router = Router();
|
||||
|
@ -8,10 +8,11 @@ import {
|
||||
trimSpecial,
|
||||
Channel,
|
||||
DMChannel,
|
||||
UserModel
|
||||
} from "@fosscord/server-util";
|
||||
UserModel,
|
||||
emitEvent
|
||||
} from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { emitEvent } from "../../../util/Event";
|
||||
|
||||
import { DmChannelCreateSchema } from "../../../schema/Channel";
|
||||
import { check } from "../../../util/instanceOf";
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Router, Request, Response } from "express";
|
||||
import { GuildModel, MemberModel, UserModel } from "@fosscord/server-util";
|
||||
import { GuildModel, MemberModel, UserModel } from "@fosscord/util";
|
||||
import bcrypt from "bcrypt";
|
||||
const router = Router();
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { UserModel } from "@fosscord/server-util";
|
||||
import { UserModel } from "@fosscord/util";
|
||||
import { Router, Response, Request } from "express";
|
||||
import bcrypt from "bcrypt";
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Router, Request, Response } from "express";
|
||||
import { GuildModel, MemberModel, UserModel, GuildDeleteEvent, GuildMemberRemoveEvent, toObject } from "@fosscord/server-util";
|
||||
import { GuildModel, MemberModel, UserModel, GuildDeleteEvent, GuildMemberRemoveEvent, toObject, emitEvent } from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { emitEvent } from "../../../util/Event";
|
||||
|
||||
import { getPublicUser } from "../../../util/User";
|
||||
|
||||
const router: Router = Router();
|
||||
@ -32,10 +32,10 @@ router.delete("/:id", async (req: Request, res: Response) => {
|
||||
emitEvent({
|
||||
event: "GUILD_DELETE",
|
||||
data: {
|
||||
id: guild_id,
|
||||
id: guild_id
|
||||
},
|
||||
user_id: req.user_id,
|
||||
} as GuildDeleteEvent),
|
||||
user_id: req.user_id
|
||||
} as GuildDeleteEvent)
|
||||
]);
|
||||
|
||||
const user = await getPublicUser(req.user_id);
|
||||
@ -44,9 +44,9 @@ router.delete("/:id", async (req: Request, res: Response) => {
|
||||
event: "GUILD_MEMBER_REMOVE",
|
||||
data: {
|
||||
guild_id: guild_id,
|
||||
user: user,
|
||||
user: user
|
||||
},
|
||||
guild_id: guild_id,
|
||||
guild_id: guild_id
|
||||
} as GuildMemberRemoveEvent);
|
||||
|
||||
return res.sendStatus(204);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Router, Request, Response } from "express";
|
||||
import { UserModel, toObject, PublicUserProjection } from "@fosscord/server-util";
|
||||
import { UserModel, toObject, PublicUserProjection } from "@fosscord/util";
|
||||
import { getPublicUser } from "../../../util/User";
|
||||
import { UserModifySchema } from "../../../schema/User";
|
||||
import { check } from "../../../util/instanceOf";
|
||||
|
@ -5,11 +5,12 @@ import {
|
||||
toObject,
|
||||
RelationshipType,
|
||||
RelationshipRemoveEvent,
|
||||
UserDocument
|
||||
} from "@fosscord/server-util";
|
||||
UserDocument,
|
||||
emitEvent
|
||||
} from "@fosscord/util";
|
||||
import { Router, Response, Request } from "express";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { emitEvent } from "../../../util/Event";
|
||||
|
||||
import { check, Length } from "../../../util/instanceOf";
|
||||
|
||||
const router = Router();
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ChannelType } from "@fosscord/server-util";
|
||||
import { ChannelType } from "@fosscord/util";
|
||||
import { Length } from "../util/instanceOf";
|
||||
|
||||
export const ChannelModifySchema = {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ChannelSchema, GuildChannel } from "@fosscord/server-util";
|
||||
import { ChannelSchema, GuildChannel } from "@fosscord/util";
|
||||
import { Length } from "../util/instanceOf";
|
||||
|
||||
export const GuildCreateSchema = {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Embed, EmbedImage } from "@fosscord/server-util";
|
||||
import { Embed, EmbedImage } from "@fosscord/util";
|
||||
import { Length } from "../util/instanceOf";
|
||||
|
||||
export const MessageCreateSchema = {
|
||||
|
@ -1,3 +1,3 @@
|
||||
import { Snowflake } from "@fosscord/server-util";
|
||||
import { Snowflake } from "@fosscord/util";
|
||||
|
||||
console.log(Snowflake.deconstruct("0"));
|
||||
|
@ -2,18 +2,18 @@ import {
|
||||
ChannelCreateEvent,
|
||||
ChannelModel,
|
||||
ChannelType,
|
||||
emitEvent,
|
||||
getPermission,
|
||||
GuildModel,
|
||||
Snowflake,
|
||||
TextChannel,
|
||||
toObject,
|
||||
VoiceChannel
|
||||
} from "@fosscord/server-util";
|
||||
} from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { emitEvent } from "./Event";
|
||||
|
||||
// TODO: DM channel
|
||||
export async function createChannel(channel: Partial<TextChannel | VoiceChannel>, user_id: string = "0") {
|
||||
|
||||
// Always check if user has permission first
|
||||
const permissions = await getPermission(user_id, channel.guild_id);
|
||||
permissions.hasThrow("MANAGE_CHANNELS");
|
||||
@ -50,7 +50,7 @@ export async function createChannel(channel: Partial<TextChannel | VoiceChannel>
|
||||
recipient_ids: null
|
||||
}).save();
|
||||
|
||||
await emitEvent({ event: "CHANNEL_CREATE", data: channel, guild_id: channel.guild_id } as ChannelCreateEvent);
|
||||
await emitEvent({ event: "CHANNEL_CREATE", data: toObject(channel), guild_id: channel.guild_id } as ChannelCreateEvent);
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
// @ts-nocheck
|
||||
import Ajv, { JSONSchemaType } from "ajv";
|
||||
import { getConfigPathForFile } from "@fosscord/server-util/dist/util/Config";
|
||||
import { Config } from "@fosscord/server-util";
|
||||
import { getConfigPathForFile } from "@fosscord/util/dist/util/Config";
|
||||
import { Config } from "@fosscord/util";
|
||||
|
||||
export interface RateLimitOptions {
|
||||
count: number;
|
||||
|
@ -1,26 +0,0 @@
|
||||
import { Config, Event, EventModel, RabbitMQ } from "@fosscord/server-util";
|
||||
|
||||
export async function emitEvent(payload: Omit<Event, "created_at">) {
|
||||
if (RabbitMQ.connection) {
|
||||
const id = (payload.channel_id || payload.user_id || payload.guild_id) as string;
|
||||
if (!id) console.error("event doesn't contain any id", payload);
|
||||
const data = typeof payload.data === "object" ? JSON.stringify(payload.data) : payload.data; // use rabbitmq for event transmission
|
||||
await RabbitMQ.channel?.assertExchange(id, "fanout", { durable: false });
|
||||
|
||||
// assertQueue isn't needed, because a queue will automatically created if it doesn't exist
|
||||
const successful = RabbitMQ.channel?.publish(id, "", Buffer.from(`${data}`), { type: payload.event });
|
||||
if (!successful) throw new Error("failed to send event");
|
||||
} else {
|
||||
// use mongodb for event transmission
|
||||
// TODO: use event emitter for local server bundle
|
||||
const obj = {
|
||||
created_at: new Date(), // in seconds
|
||||
...payload
|
||||
};
|
||||
// TODO: bigint isn't working
|
||||
|
||||
return await new EventModel(obj).save();
|
||||
}
|
||||
}
|
||||
|
||||
export async function emitAuditLog(payload: any) {}
|
@ -11,11 +11,12 @@ import {
|
||||
toObject,
|
||||
UserModel,
|
||||
GuildDocument,
|
||||
Config
|
||||
} from "@fosscord/server-util";
|
||||
Config,
|
||||
emitEvent
|
||||
} from "@fosscord/util";
|
||||
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { emitEvent } from "./Event";
|
||||
|
||||
import { getPublicUser } from "./User";
|
||||
|
||||
export const PublicMemberProjection = {
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { ChannelModel, Embed, Message, MessageCreateEvent, MessageUpdateEvent } from "@fosscord/server-util";
|
||||
import { Snowflake } from "@fosscord/server-util";
|
||||
import { MessageModel } from "@fosscord/server-util";
|
||||
import { PublicMemberProjection } from "@fosscord/server-util";
|
||||
import { toObject } from "@fosscord/server-util";
|
||||
import { getPermission } from "@fosscord/server-util";
|
||||
import { ChannelModel, Embed, emitEvent, Message, MessageCreateEvent, MessageUpdateEvent } from "@fosscord/util";
|
||||
import { Snowflake } from "@fosscord/util";
|
||||
import { MessageModel } from "@fosscord/util";
|
||||
import { PublicMemberProjection } from "@fosscord/util";
|
||||
import { toObject } from "@fosscord/util";
|
||||
import { getPermission } from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import fetch from "node-fetch";
|
||||
import cheerio from "cheerio";
|
||||
import { emitEvent } from "./Event";
|
||||
import { MessageType } from "@fosscord/server-util/dist/util/Constants";
|
||||
|
||||
import { MessageType } from "@fosscord/util/dist/util/Constants";
|
||||
// TODO: check webhook, application, system author
|
||||
|
||||
const LINK_REGEX = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { toObject, UserModel, PublicUserProjection } from "@fosscord/server-util";
|
||||
import { toObject, UserModel, PublicUserProjection } from "@fosscord/util";
|
||||
import { HTTPError } from "lambert-server";
|
||||
|
||||
export { PublicUserProjection };
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Config } from "@fosscord/server-util";
|
||||
import { Config } from "@fosscord/util";
|
||||
import FormData from "form-data";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import fetch from "node-fetch";
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Config } from "@fosscord/server-util";
|
||||
import { Config } from "@fosscord/util";
|
||||
import { Request } from "express";
|
||||
// use ipdata package instead of simple fetch because of integrated caching
|
||||
import fetch from "node-fetch";
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Config } from "@fosscord/server-util";
|
||||
import { Config } from "@fosscord/util";
|
||||
import "missing-native-js-functions";
|
||||
|
||||
const reNUMBER = /[0-9]/g;
|
||||
|
2750
bundle/package-lock.json
generated
Normal file
2750
bundle/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
42
bundle/package.json
Normal file
42
bundle/package.json
Normal file
@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "@fosscord/server",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "src/start.js",
|
||||
"scripts": {
|
||||
"linkInstall": "npm run --prefix ../util/ link && npm run --prefix ../api/ link && npm run --prefix ../cdn/ link && npm run --prefix ../gateway/ link",
|
||||
"postinstall": "npm run linkInstall && npm link @fosscord/util && npm link @fosscord/api && npm link @fosscord/gateway && npm link @fosscord/cdn",
|
||||
"build": "tsc -b .",
|
||||
"start": "npm run build && node dist/start.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/fosscord/fosscord-api.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Fosscord",
|
||||
"license": "AGPLV3",
|
||||
"bugs": {
|
||||
"url": "https://github.com/fosscord/fosscord-api/issues"
|
||||
},
|
||||
"homepage": "https://github.com/fosscord/fosscord-api#readme",
|
||||
"devDependencies": {
|
||||
"@types/async-exit-hook": "^2.0.0",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/node": "^16.6.1",
|
||||
"@types/node-os-utils": "^1.2.0",
|
||||
"typescript": "^4.3.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fosscord/api": "file:../api",
|
||||
"@fosscord/cdn": "file:../cdn",
|
||||
"@fosscord/gateway": "file:../gateway",
|
||||
"@fosscord/util": "file:../util",
|
||||
"async-exit-hook": "^2.0.1",
|
||||
"express": "^4.17.1",
|
||||
"link": "^0.1.5",
|
||||
"mongodb-memory-server-global-4.4": "^7.3.6",
|
||||
"node-os-utils": "^1.3.5"
|
||||
}
|
||||
}
|
33
bundle/src/Server.ts
Normal file
33
bundle/src/Server.ts
Normal file
@ -0,0 +1,33 @@
|
||||
process.on("unhandledRejection", console.error);
|
||||
process.on("uncaughtException", console.error);
|
||||
|
||||
import http from "http";
|
||||
import { FosscordServer as APIServer } from "@fosscord/api";
|
||||
import { Server as GatewayServer } from "@fosscord/gateway";
|
||||
import { CDNServer } from "@fosscord/cdn/";
|
||||
import express from "express";
|
||||
import { Config } from "../../util/dist";
|
||||
|
||||
const app = express();
|
||||
const server = http.createServer();
|
||||
const port = Number(process.env.PORT) || 8080;
|
||||
const production = true;
|
||||
server.on("request", app);
|
||||
|
||||
// @ts-ignore
|
||||
const api = new APIServer({ server, port, production, app });
|
||||
// @ts-ignore
|
||||
const cdn = new CDNServer({ server, port, production, app });
|
||||
// @ts-ignore
|
||||
const gateway = new GatewayServer({ server, port, production });
|
||||
|
||||
async function main() {
|
||||
await api.start();
|
||||
await cdn.start();
|
||||
await gateway.start();
|
||||
|
||||
if (!Config.get().gateway.endpoint) await Config.set({ gateway: { endpoint: `ws://localhost:${port}` } });
|
||||
if (!Config.get().cdn.endpoint) await Config.set({ cdn: { endpoint: `http://localhost:${port}` } });
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
74
bundle/src/start.ts
Normal file
74
bundle/src/start.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import fs from "fs";
|
||||
import { MongoMemoryServer } from "mongodb-memory-server-global-4.4";
|
||||
import path from "path";
|
||||
import cluster from "cluster";
|
||||
import os from "os";
|
||||
import osu from "node-os-utils";
|
||||
import exitHook from "async-exit-hook";
|
||||
|
||||
const cores = Number(process.env.threads) || 1 || os.cpus().length;
|
||||
|
||||
if (cluster.isMaster && !process.env.masterStarted) {
|
||||
const dbPath = path.join(__dirname, "..", "..", "db");
|
||||
const dbName = "fosscord";
|
||||
const storageEngine = "wiredTiger";
|
||||
const port = 27020;
|
||||
const ip = "127.0.0.1";
|
||||
var mongod: MongoMemoryServer;
|
||||
fs.mkdirSync(dbPath, { recursive: true });
|
||||
|
||||
exitHook((callback: any) => {
|
||||
(async () => {
|
||||
console.log(`Stopping MongoDB ...`);
|
||||
await mongod.stop();
|
||||
console.log(`Stopped MongoDB`);
|
||||
callback();
|
||||
})();
|
||||
});
|
||||
|
||||
process.env.masterStarted = "true";
|
||||
|
||||
setInterval(async () => {
|
||||
const [cpuUsed, memory, network] = await Promise.all([osu.cpu.usage(), osu.mem.info(), osu.netstat.inOut()]);
|
||||
if (typeof network === "object") {
|
||||
console.log(`Network: in ${network.total.inputMb}mb | out ${network.total.outputMb}mb`);
|
||||
}
|
||||
|
||||
console.log(
|
||||
`[CPU] ${cpuUsed.toFixed(2)}% | [Memory] ${memory.usedMemMb.toFixed(0)}mb/${memory.totalMemMb.toFixed(0)}mb`
|
||||
);
|
||||
}, 1000 * 60);
|
||||
|
||||
(async () => {
|
||||
console.log(`[Database] starting ...`);
|
||||
mongod = new MongoMemoryServer({
|
||||
instance: {
|
||||
port,
|
||||
ip,
|
||||
dbName,
|
||||
dbPath,
|
||||
storageEngine,
|
||||
auth: false, // by default `mongod` is started with '--noauth', start `mongod` with '--auth'
|
||||
},
|
||||
});
|
||||
await mongod.start();
|
||||
process.env.MONGO_URL = mongod.getUri(dbName);
|
||||
|
||||
console.log(`[CPU] ${osu.cpu.model()} Cores x${osu.cpu.count()}`);
|
||||
console.log(`[System] ${await osu.os.oos()} ${os.arch()}`);
|
||||
console.log(`[Database] started`);
|
||||
console.log(`[Process] running with pid: ${process.pid}`);
|
||||
|
||||
// Fork workers.
|
||||
for (let i = 0; i < cores; i++) {
|
||||
cluster.fork();
|
||||
}
|
||||
|
||||
cluster.on("exit", (worker: any, code: any, signal: any) => {
|
||||
console.log(`[Worker] died with pid: ${worker.process.pid} , restarting ...`);
|
||||
cluster.fork();
|
||||
});
|
||||
})();
|
||||
} else {
|
||||
require("./Server.js");
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"target": "ES2020" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
|
||||
"target": "ESNext" /* 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'. */,
|
||||
"lib": ["ES2020"] /* Specify library files to be included in the compilation. */,
|
||||
"allowJs": true /* Allow javascript files to be compiled. */,
|
||||
@ -43,8 +43,6 @@
|
||||
|
||||
/* Module Resolution Options */
|
||||
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||
"types": ["node"] /* Type declaration files to be included in compilation. */,
|
@ -5,6 +5,8 @@
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"link": "npm run build && npm link",
|
||||
"postinstall": "npm run --prefix ../util/ link && npm link @fosscord/util && npm run link",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "tsc -b .",
|
||||
"start": "npm run build && node dist/start.js"
|
||||
@ -21,7 +23,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/discord-open-source/discord-cdn#readme",
|
||||
"dependencies": {
|
||||
"@fosscord/server-util": "file:../util",
|
||||
"@fosscord/util": "file:../util",
|
||||
"body-parser": "^1.19.0",
|
||||
"btoa": "^1.2.1",
|
||||
"cheerio": "^1.0.0-rc.5",
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Server, ServerOptions } from "lambert-server";
|
||||
import { Config, db } from "@fosscord/server-util";
|
||||
import { Config, db } from "@fosscord/util";
|
||||
import path from "path";
|
||||
import avatarsRoute from "./routes/avatars";
|
||||
|
||||
@ -13,11 +13,9 @@ export class CDNServer extends Server {
|
||||
}
|
||||
|
||||
async start() {
|
||||
console.log("[Database] connecting ...");
|
||||
// @ts-ignore
|
||||
await (db as Promise<Connection>);
|
||||
await Config.init();
|
||||
console.log("[Database] connected");
|
||||
this.app.use((req, res, next) => {
|
||||
res.set("Access-Control-Allow-Origin", "*");
|
||||
// TODO: use better CSP policy
|
||||
@ -33,31 +31,31 @@ export class CDNServer extends Server {
|
||||
await this.registerRoutes(path.join(__dirname, "routes/"));
|
||||
|
||||
this.app.use("/icons/", avatarsRoute);
|
||||
this.log("info", "[Server] Route /icons registered");
|
||||
this.log("verbose", "[Server] Route /icons registered");
|
||||
|
||||
this.app.use("/emojis/", avatarsRoute);
|
||||
this.log("info", "[Server] Route /emojis registered");
|
||||
this.log("verbose", "[Server] Route /emojis registered");
|
||||
|
||||
this.app.use("/stickers/", avatarsRoute);
|
||||
this.log("info", "[Server] Route /stickers registered");
|
||||
this.log("verbose", "[Server] Route /stickers registered");
|
||||
|
||||
this.app.use("/banners/", avatarsRoute);
|
||||
this.log("info", "[Server] Route /banners registered");
|
||||
this.log("verbose", "[Server] Route /banners registered");
|
||||
|
||||
this.app.use("/splashes/", avatarsRoute);
|
||||
this.log("info", "[Server] Route /splashes registered");
|
||||
this.log("verbose", "[Server] Route /splashes registered");
|
||||
|
||||
this.app.use("/app-icons/", avatarsRoute);
|
||||
this.log("info", "[Server] Route /app-icons registered");
|
||||
this.log("verbose", "[Server] Route /app-icons registered");
|
||||
|
||||
this.app.use("/app-assets/", avatarsRoute);
|
||||
this.log("info", "[Server] Route /app-assets registered");
|
||||
this.log("verbose", "[Server] Route /app-assets registered");
|
||||
|
||||
this.app.use("/discover-splashes/", avatarsRoute);
|
||||
this.log("info", "[Server] Route /discover-splashes registered");
|
||||
this.log("verbose", "[Server] Route /discover-splashes registered");
|
||||
|
||||
this.app.use("/team-icons/", avatarsRoute);
|
||||
this.log("info", "[Server] Route /team-icons registered");
|
||||
this.log("verbose", "[Server] Route /team-icons registered");
|
||||
|
||||
return super.start();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import { Config, Snowflake } from "@fosscord/server-util";
|
||||
import { Config, Snowflake } from "@fosscord/util";
|
||||
import { storage } from "../util/Storage";
|
||||
import FileType from "file-type";
|
||||
import { HTTPError } from "lambert-server";
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import { Config, Snowflake } from "@fosscord/server-util";
|
||||
import { Config, Snowflake } from "@fosscord/util";
|
||||
import { storage } from "../util/Storage";
|
||||
import FileType from "file-type";
|
||||
import { HTTPError } from "lambert-server";
|
||||
|
@ -4,7 +4,7 @@ import { Router, Response, Request } from "express";
|
||||
import fetch from "node-fetch";
|
||||
import crypto from "crypto";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { Snowflake } from "@fosscord/server-util";
|
||||
import { Snowflake } from "@fosscord/util";
|
||||
import { storage } from "../util/Storage";
|
||||
|
||||
const router = Router();
|
||||
|
24
docker-compose.yml
Normal file
24
docker-compose.yml
Normal file
@ -0,0 +1,24 @@
|
||||
version: "3"
|
||||
services:
|
||||
db:
|
||||
hostname: fosscord_db
|
||||
image: mongo:latest
|
||||
volumes:
|
||||
- ./db:/data/db
|
||||
restart: unless-stopped
|
||||
api:
|
||||
hostname: fosscord_api
|
||||
image: fosscord/api
|
||||
depends_on:
|
||||
- db
|
||||
ports:
|
||||
- 3001:3001
|
||||
env_file: ./.docker/env
|
||||
gateway:
|
||||
hostname: fosscord_gateway
|
||||
image: fosscord/gateway
|
||||
depends_on:
|
||||
- db
|
||||
ports:
|
||||
- 3002:3002
|
||||
env_file: ./.docker/env
|
47
gateway/.github/workflows/docker-publish.yml
vendored
47
gateway/.github/workflows/docker-publish.yml
vendored
@ -1,47 +0,0 @@
|
||||
name: docker-publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
-
|
||||
name: Cache Docker layers
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ secrets.DOCKERHUB_TAGS }}
|
||||
cache-from: type=local,src=/tmp/.buildx-cache
|
||||
cache-to: type=local,dest=/tmp/.buildx-cache-new
|
||||
-
|
||||
# Hackfix to cleanup cache; replace after buildx 0.6 and BuildKit 0.9 are released
|
||||
# https://github.com/docker/build-push-action/pull/406#issuecomment-879184394
|
||||
name: Move cache fix
|
||||
run: |
|
||||
rm -rf /tmp/.buildx-cache
|
||||
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
|
@ -4,16 +4,18 @@
|
||||
"description": "",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"link": "npm run build && npm link",
|
||||
"postinstall": "npm run --prefix ../util/ link && npm link @fosscord/util && npm run link",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "npm run build && node dist/start.js",
|
||||
"build": "npx tsc -b .",
|
||||
"build": "tsc -b .",
|
||||
"dev": "tsnd --respawn src/start.ts"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Fosscord",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@fosscord/server-util": "file:../util",
|
||||
"@fosscord/util": "file:../util",
|
||||
"ajv": "^8.5.0",
|
||||
"amqplib": "^0.8.0",
|
||||
"dotenv": "^8.2.0",
|
||||
|
@ -1,7 +1,7 @@
|
||||
import "missing-native-js-functions";
|
||||
import dotenv from "dotenv";
|
||||
dotenv.config();
|
||||
import { Config, db, RabbitMQ } from "@fosscord/server-util";
|
||||
import { Config, db, initEvent, RabbitMQ } from "@fosscord/util";
|
||||
import { Server as WebSocketServer } from "ws";
|
||||
import { Connection } from "./events/Connection";
|
||||
import http from "http";
|
||||
@ -40,8 +40,7 @@ export class Server {
|
||||
await (db as Promise<Connection>);
|
||||
await this.setupSchema();
|
||||
await Config.init();
|
||||
await RabbitMQ.init();
|
||||
console.log("[Database] connected");
|
||||
await initEvent();
|
||||
if (!this.server.listening) {
|
||||
this.server.listen(this.port);
|
||||
console.log(`[Gateway] online on 0.0.0.0:${this.port}`);
|
||||
|
@ -40,6 +40,7 @@ export async function Connection(this: Server, socket: WebSocket, request: Incom
|
||||
socket.deflate.on("data", (chunk) => socket.send(chunk));
|
||||
}
|
||||
|
||||
socket.events = {};
|
||||
socket.permissions = {};
|
||||
socket.sequence = 0;
|
||||
|
||||
|
@ -1,63 +1,31 @@
|
||||
import {
|
||||
db,
|
||||
Event,
|
||||
MongooseCache,
|
||||
UserModel,
|
||||
getPermission,
|
||||
Permissions,
|
||||
ChannelModel,
|
||||
RabbitMQ,
|
||||
EVENT,
|
||||
} from "@fosscord/server-util";
|
||||
listenEvent,
|
||||
EventOpts,
|
||||
ListenEventOpts,
|
||||
} from "@fosscord/util";
|
||||
import { OPCODES } from "../util/Constants";
|
||||
import { Send } from "../util/Send";
|
||||
import WebSocket from "../util/WebSocket";
|
||||
import "missing-native-js-functions";
|
||||
import { ConsumeMessage } from "amqplib";
|
||||
import { Channel } from "amqplib";
|
||||
|
||||
// TODO: close connection on Invalidated Token
|
||||
// TODO: check intent
|
||||
// TODO: Guild Member Update is sent for current-user updates regardless of whether the GUILD_MEMBERS intent is set.
|
||||
// ? How to resubscribe MongooseCache for new dm channel events? Maybe directly send them to the user_id regardless of the channel_id? -> max overhead of creating 10 events in database for dm user group. Or a new field in event -> recipient_ids?
|
||||
|
||||
// Sharding: calculate if the current shard id matches the formula: shard_id = (guild_id >> 22) % num_shards
|
||||
// https://discord.com/developers/docs/topics/gateway#sharding
|
||||
|
||||
export interface DispatchOpts {
|
||||
eventStream: MongooseCache;
|
||||
guilds: Array<string>;
|
||||
}
|
||||
|
||||
function getPipeline(this: WebSocket, guilds: string[], channels: string[] = []) {
|
||||
if (this.shard_count) {
|
||||
guilds = guilds.filter((x) => (BigInt(x) >> 22n) % this.shard_count! === this.shard_id);
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
$match: {
|
||||
$or: [
|
||||
{ "fullDocument.guild_id": { $in: guilds } },
|
||||
{ "fullDocument.user_id": this.user_id },
|
||||
{ "fullDocument.channel_id": { $in: channels } },
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
async function rabbitListen(this: WebSocket, id: string) {
|
||||
await this.rabbitCh!.assertExchange(id, "fanout", { durable: false });
|
||||
const q = await this.rabbitCh!.assertQueue("", { exclusive: true, autoDelete: true });
|
||||
|
||||
this.rabbitCh!.bindQueue(q.queue, id, "");
|
||||
this.rabbitCh!.consume(q.queue, consume.bind(this), {
|
||||
noAck: false,
|
||||
});
|
||||
this.rabbitCh!.queues[id] = q.queue;
|
||||
}
|
||||
|
||||
// TODO: use already required guilds/channels of Identify and don't fetch them again
|
||||
// TODO: use already queried guilds/channels of Identify and don't fetch them again
|
||||
export async function setupListener(this: WebSocket) {
|
||||
const user = await UserModel.findOne({ id: this.user_id }, { guilds: true }).exec();
|
||||
const channels = await ChannelModel.find(
|
||||
@ -67,26 +35,32 @@ export async function setupListener(this: WebSocket) {
|
||||
const dm_channels = channels.filter((x) => !x.guild_id);
|
||||
const guild_channels = channels.filter((x) => x.guild_id);
|
||||
|
||||
if (RabbitMQ.connection) {
|
||||
// @ts-ignore
|
||||
this.rabbitCh = await RabbitMQ.connection.createChannel();
|
||||
this.rabbitCh!.queues = {};
|
||||
const opts: { acknowledge: boolean; channel?: Channel } = { acknowledge: true };
|
||||
const consumer = consume.bind(this);
|
||||
|
||||
rabbitListen.call(this, this.user_id);
|
||||
if (RabbitMQ.connection) {
|
||||
opts.channel = await RabbitMQ.connection.createChannel();
|
||||
// @ts-ignore
|
||||
opts.channel.queues = {};
|
||||
}
|
||||
|
||||
this.events[this.user_id] = await listenEvent(this.user_id, consumer, opts);
|
||||
|
||||
for (const channel of dm_channels) {
|
||||
rabbitListen.call(this, channel.id);
|
||||
this.events[channel.id] = await listenEvent(channel.id, consumer, opts);
|
||||
}
|
||||
|
||||
for (const guild of user.guilds) {
|
||||
// contains guild and dm channels
|
||||
|
||||
getPermission(this.user_id, guild)
|
||||
.then((x) => {
|
||||
.then(async (x) => {
|
||||
this.permissions[guild] = x;
|
||||
rabbitListen.call(this, guild);
|
||||
this.listeners;
|
||||
this.events[guild] = await listenEvent(guild, consumer, opts);
|
||||
for (const channel of guild_channels) {
|
||||
if (x.overwriteChannel(channel.permission_overwrites).has("VIEW_CHANNEL")) {
|
||||
rabbitListen.call(this, channel.id);
|
||||
this.events[channel.id] = await listenEvent(channel.id, consumer, opts);
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -94,63 +68,44 @@ export async function setupListener(this: WebSocket) {
|
||||
}
|
||||
|
||||
this.once("close", () => {
|
||||
this.rabbitCh!.close();
|
||||
if (opts.channel) opts.channel.close();
|
||||
else Object.values(this.events).forEach((x) => x());
|
||||
});
|
||||
} else {
|
||||
const eventStream = new MongooseCache(
|
||||
db.collection("events"),
|
||||
getPipeline.call(
|
||||
this,
|
||||
user.guilds,
|
||||
channels.map((x) => x.id)
|
||||
),
|
||||
{
|
||||
onlyEvents: true,
|
||||
}
|
||||
);
|
||||
|
||||
await eventStream.init();
|
||||
eventStream.on("insert", (document: Event) =>
|
||||
dispatch.call(this, document, { eventStream, guilds: user.guilds })
|
||||
);
|
||||
|
||||
this.once("close", () => eventStream.destroy());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: use rabbitmq to only receive events that are included in intents
|
||||
function consume(this: WebSocket, opts: ConsumeMessage | null) {
|
||||
if (!opts) return;
|
||||
if (!this.rabbitCh) return;
|
||||
const data = JSON.parse(opts.content.toString());
|
||||
// TODO: only subscribe for events that are in the connection intents
|
||||
function consume(this: WebSocket, opts: EventOpts) {
|
||||
const { data, event } = opts;
|
||||
const id = data.id as string;
|
||||
const event = opts.properties.type as EVENT;
|
||||
const permission = this.permissions[id] || new Permissions("ADMINISTRATOR"); // default permission for dm
|
||||
|
||||
console.log("rabbitmq event", event);
|
||||
const consumer = consume.bind(this);
|
||||
const listenOpts = opts as ListenEventOpts;
|
||||
console.log("event", event);
|
||||
|
||||
// subscription managment
|
||||
switch (event) {
|
||||
case "CHANNEL_DELETE":
|
||||
case "GUILD_DELETE":
|
||||
this.rabbitCh.cancel(id);
|
||||
delete this.events[id];
|
||||
opts.cancel();
|
||||
break;
|
||||
case "CHANNEL_CREATE":
|
||||
if (!permission.overwriteChannel(data.permission_overwrites).has("VIEW_CHANNEL")) return;
|
||||
// TODO: check if user has permission to channel
|
||||
case "GUILD_CREATE":
|
||||
rabbitListen.call(this, id);
|
||||
listenEvent(id, consumer, listenOpts);
|
||||
break;
|
||||
case "CHANNEL_UPDATE":
|
||||
const queue_id = this.rabbitCh.queues[id];
|
||||
const exists = this.events[id];
|
||||
// @ts-ignore
|
||||
const exists = this.rabbitCh.consumers[id];
|
||||
if (permission.overwriteChannel(data.permission_overwrites).has("VIEW_CHANNEL")) {
|
||||
if (exists) break;
|
||||
rabbitListen.call(this, id);
|
||||
listenEvent(id, consumer, listenOpts);
|
||||
} else {
|
||||
if (!exists) break;
|
||||
this.rabbitCh.cancel(queue_id);
|
||||
this.rabbitCh.unbindQueue(queue_id, id, "");
|
||||
if (!exists) return; // return -> do not send channel update events for hidden channels
|
||||
opts.cancel(id);
|
||||
delete this.events[id];
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -216,167 +171,5 @@ function consume(this: WebSocket, opts: ConsumeMessage | null) {
|
||||
d: data,
|
||||
s: this.sequence++,
|
||||
});
|
||||
this.rabbitCh.ack(opts);
|
||||
}
|
||||
|
||||
// TODO: cache permission
|
||||
// we shouldn't fetch the permission for every event, as a message send event with many channel members would result in many thousand db queries.
|
||||
// instead we should calculate all (guild, channel) permissions once and dynamically update if it changes.
|
||||
// TODO: only subscribe for events that are in the connection intents
|
||||
// TODO: only subscribe for channel/guilds that the user has access to (and re-subscribe if it changes)
|
||||
|
||||
export async function dispatch(this: WebSocket, document: Event, { eventStream, guilds }: DispatchOpts) {
|
||||
var permission = new Permissions("ADMINISTRATOR"); // default permission for dms
|
||||
console.log("event", document);
|
||||
var channel_id = document.channel_id || document.data?.channel_id;
|
||||
// TODO: clean up
|
||||
if (document.event === "GUILD_CREATE") {
|
||||
guilds.push(document.data.id);
|
||||
eventStream.changeStream(getPipeline.call(this, guilds));
|
||||
} else if (document.event === "GUILD_DELETE") {
|
||||
guilds.remove(document.guild_id!);
|
||||
eventStream.changeStream(getPipeline.call(this, guilds));
|
||||
} else if (document.event === "CHANNEL_DELETE") channel_id = null;
|
||||
if (document.guild_id && !this.intents.has("GUILDS")) return;
|
||||
|
||||
try {
|
||||
permission = await getPermission(this.user_id, document.guild_id, channel_id);
|
||||
} catch (e) {
|
||||
permission = new Permissions();
|
||||
}
|
||||
|
||||
// check intents: https://discord.com/developers/docs/topics/gateway#gateway-intents
|
||||
switch (document.event) {
|
||||
case "GUILD_DELETE":
|
||||
case "GUILD_CREATE":
|
||||
case "GUILD_UPDATE":
|
||||
case "GUILD_ROLE_CREATE":
|
||||
case "GUILD_ROLE_UPDATE":
|
||||
case "GUILD_ROLE_DELETE":
|
||||
case "CHANNEL_CREATE":
|
||||
case "CHANNEL_DELETE":
|
||||
case "CHANNEL_UPDATE":
|
||||
// gets sent if GUILDS intent is set (already checked in if document.guild_id)
|
||||
break;
|
||||
case "GUILD_INTEGRATIONS_UPDATE":
|
||||
if (!this.intents.has("GUILD_INTEGRATIONS")) return;
|
||||
break;
|
||||
case "WEBHOOKS_UPDATE":
|
||||
if (!this.intents.has("GUILD_WEBHOOKS")) return;
|
||||
break;
|
||||
case "GUILD_EMOJI_UPDATE":
|
||||
if (!this.intents.has("GUILD_EMOJIS")) return;
|
||||
break;
|
||||
// only send them, if the user subscribed for this part of the member list, or is a bot
|
||||
case "GUILD_MEMBER_ADD":
|
||||
case "GUILD_MEMBER_REMOVE":
|
||||
case "GUILD_MEMBER_UPDATE":
|
||||
if (!this.intents.has("GUILD_MEMBERS")) return;
|
||||
break;
|
||||
case "VOICE_STATE_UPDATE":
|
||||
if (!this.intents.has("GUILD_VOICE_STATES")) return;
|
||||
break;
|
||||
case "GUILD_BAN_ADD":
|
||||
case "GUILD_BAN_REMOVE":
|
||||
if (!this.intents.has("GUILD_BANS")) return;
|
||||
break;
|
||||
case "INVITE_CREATE":
|
||||
case "INVITE_DELETE":
|
||||
if (!this.intents.has("GUILD_INVITES")) return;
|
||||
case "PRESENCE_UPDATE":
|
||||
if (!this.intents.has("GUILD_PRESENCES")) return;
|
||||
break;
|
||||
case "MESSAGE_CREATE":
|
||||
case "MESSAGE_DELETE":
|
||||
case "MESSAGE_DELETE_BULK":
|
||||
case "MESSAGE_UPDATE":
|
||||
case "CHANNEL_PINS_UPDATE":
|
||||
if (!this.intents.has("GUILD_MESSAGES") && document.guild_id) return;
|
||||
if (!this.intents.has("DIRECT_MESSAGES") && !document.guild_id) return;
|
||||
break;
|
||||
case "MESSAGE_REACTION_ADD":
|
||||
case "MESSAGE_REACTION_REMOVE":
|
||||
case "MESSAGE_REACTION_REMOVE_ALL":
|
||||
case "MESSAGE_REACTION_REMOVE_EMOJI":
|
||||
if (!this.intents.has("GUILD_MESSAGE_REACTIONS") && document.guild_id) return;
|
||||
if (!this.intents.has("DIRECT_MESSAGE_REACTIONS") && !document.guild_id) return;
|
||||
break;
|
||||
|
||||
case "TYPING_START":
|
||||
if (!this.intents.has("GUILD_MESSAGE_TYPING") && document.guild_id) return;
|
||||
if (!this.intents.has("DIRECT_MESSAGE_TYPING") && !document.guild_id) return;
|
||||
break;
|
||||
case "READY": // will be sent by the gateway
|
||||
case "USER_UPDATE":
|
||||
case "APPLICATION_COMMAND_CREATE":
|
||||
case "APPLICATION_COMMAND_DELETE":
|
||||
case "APPLICATION_COMMAND_UPDATE":
|
||||
default:
|
||||
// Any events not defined in an intent are considered "passthrough" and will always be sent to you.
|
||||
break;
|
||||
}
|
||||
|
||||
// check permissions
|
||||
switch (document.event) {
|
||||
case "GUILD_INTEGRATIONS_UPDATE":
|
||||
if (!permission.has("MANAGE_GUILD")) return;
|
||||
break;
|
||||
case "WEBHOOKS_UPDATE":
|
||||
if (!permission.has("MANAGE_WEBHOOKS")) return;
|
||||
break;
|
||||
case "GUILD_MEMBER_ADD":
|
||||
case "GUILD_MEMBER_REMOVE":
|
||||
case "GUILD_MEMBER_UPDATE":
|
||||
// only send them, if the user subscribed for this part of the member list, or is a bot
|
||||
break;
|
||||
case "GUILD_BAN_ADD":
|
||||
case "GUILD_BAN_REMOVE":
|
||||
if (!permission.has("BAN_MEMBERS")) break;
|
||||
break;
|
||||
case "INVITE_CREATE":
|
||||
case "INVITE_DELETE":
|
||||
if (!permission.has("MANAGE_GUILD")) break;
|
||||
case "PRESENCE_UPDATE":
|
||||
break;
|
||||
case "VOICE_STATE_UPDATE":
|
||||
case "MESSAGE_CREATE":
|
||||
case "MESSAGE_DELETE":
|
||||
case "MESSAGE_DELETE_BULK":
|
||||
case "MESSAGE_UPDATE":
|
||||
case "CHANNEL_PINS_UPDATE":
|
||||
case "MESSAGE_REACTION_ADD":
|
||||
case "MESSAGE_REACTION_REMOVE":
|
||||
case "MESSAGE_REACTION_REMOVE_ALL":
|
||||
case "MESSAGE_REACTION_REMOVE_EMOJI":
|
||||
case "TYPING_START":
|
||||
// only gets send if the user is alowed to view the current channel
|
||||
if (!permission.has("VIEW_CHANNEL")) return;
|
||||
break;
|
||||
case "GUILD_CREATE":
|
||||
case "GUILD_DELETE":
|
||||
case "GUILD_UPDATE":
|
||||
case "GUILD_ROLE_CREATE":
|
||||
case "GUILD_ROLE_UPDATE":
|
||||
case "GUILD_ROLE_DELETE":
|
||||
case "CHANNEL_CREATE":
|
||||
case "CHANNEL_DELETE":
|
||||
case "CHANNEL_UPDATE":
|
||||
case "GUILD_EMOJI_UPDATE":
|
||||
case "READY": // will be sent by the gateway
|
||||
case "USER_UPDATE":
|
||||
case "APPLICATION_COMMAND_CREATE":
|
||||
case "APPLICATION_COMMAND_DELETE":
|
||||
case "APPLICATION_COMMAND_UPDATE":
|
||||
default:
|
||||
// always gets sent
|
||||
// Any events not defined in an intent are considered "passthrough" and will always be sent
|
||||
break;
|
||||
}
|
||||
|
||||
return Send(this, {
|
||||
op: OPCODES.Dispatch,
|
||||
t: document.event,
|
||||
d: document.data,
|
||||
s: this.sequence++,
|
||||
});
|
||||
opts.acknowledge?.();
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import {
|
||||
toObject,
|
||||
EVENTEnum,
|
||||
Config,
|
||||
} from "@fosscord/server-util";
|
||||
} from "@fosscord/util";
|
||||
import { setupListener } from "../listener/listener";
|
||||
import { IdentifySchema } from "../schema/Identify";
|
||||
import { Send } from "../util/Send";
|
||||
|
@ -1,13 +1,5 @@
|
||||
// @ts-nocheck WIP
|
||||
import {
|
||||
db,
|
||||
getPermission,
|
||||
MemberModel,
|
||||
MongooseCache,
|
||||
PublicUserProjection,
|
||||
RoleModel,
|
||||
toObject,
|
||||
} from "@fosscord/server-util";
|
||||
import { db, getPermission, PublicUserProjection, toObject } from "@fosscord/util";
|
||||
import { LazyRequest } from "../schema/LazyRequest";
|
||||
import { OPCODES, Payload } from "../util/Constants";
|
||||
import { Send } from "../util/Send";
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ActivityBodySchema } from "@fosscord/server-util";
|
||||
import { ActivityBodySchema } from "@fosscord/util";
|
||||
import { EmojiSchema } from "./Emoji";
|
||||
|
||||
export const ActivitySchema = {
|
||||
|
@ -1,6 +1,6 @@
|
||||
// @ts-nocheck
|
||||
import { Config } from "@fosscord/server-util";
|
||||
import { getConfigPathForFile } from "@fosscord/server-util/dist/util/Config";
|
||||
import { Config } from "@fosscord/util";
|
||||
import { getConfigPathForFile } from "@fosscord/util/dist/util/Config";
|
||||
import Ajv, { JSONSchemaType } from "ajv";
|
||||
|
||||
export interface DefaultOptions {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Intents, Permissions } from "@fosscord/server-util";
|
||||
import { Intents, Permissions } from "@fosscord/util";
|
||||
import WS, { Server, Data } from "ws";
|
||||
import { Deflate } from "zlib";
|
||||
import { Channel } from "amqplib";
|
||||
@ -15,8 +15,8 @@ interface WebSocket extends WS {
|
||||
readyTimeout: NodeJS.Timeout;
|
||||
intents: Intents;
|
||||
sequence: number;
|
||||
rabbitCh?: Channel & { queues: Record<string, string> };
|
||||
permissions: Record<string, Permissions>;
|
||||
events: Record<string, Function>;
|
||||
}
|
||||
|
||||
export default WebSocket;
|
||||
|
1268
rtc/package-lock.json
generated
1268
rtc/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,48 +0,0 @@
|
||||
{
|
||||
"name": "@fosscord/server-util",
|
||||
"version": "1.3.52",
|
||||
"description": "Utility functions for the all server repositories",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "tsc -b .",
|
||||
"prepublish": "npm run build"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/fosscord/fosscord-server-util.git"
|
||||
},
|
||||
"keywords": [
|
||||
"discord",
|
||||
"fosscord",
|
||||
"fosscord-server-util",
|
||||
"discord open source",
|
||||
"discord-open-source"
|
||||
],
|
||||
"author": "Fosscord",
|
||||
"license": "GPLV3",
|
||||
"bugs": {
|
||||
"url": "https://github.com/fosscord/fosscord-server-util/issues"
|
||||
},
|
||||
"homepage": "https://docs.fosscord.com/",
|
||||
"dependencies": {
|
||||
"@types/jsonwebtoken": "^8.5.0",
|
||||
"@types/mongoose-autopopulate": "^0.10.1",
|
||||
"@types/mongoose-lean-virtuals": "^0.5.1",
|
||||
"@types/node": "^14.14.25",
|
||||
"ajv": "^8.5.0",
|
||||
"amqplib": "^0.8.0",
|
||||
"dot-prop": "^6.0.1",
|
||||
"env-paths": "^2.2.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"missing-native-js-functions": "^1.2.2",
|
||||
"mongodb": "^3.6.9",
|
||||
"mongoose": "^5.12.3",
|
||||
"mongoose-autopopulate": "^0.12.3",
|
||||
"typescript": "^4.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/amqplib": "^0.8.1"
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
export * from "./util/checkToken";
|
||||
|
||||
export * as Constants from "./util/Constants";
|
||||
export * from "./models/index";
|
||||
export * from "./util/index";
|
||||
|
||||
import Config from "./util/Config";
|
||||
import db, { MongooseCache, toObject } from "./util/Database";
|
||||
|
||||
export { Config, db, MongooseCache, toObject };
|
@ -1,132 +0,0 @@
|
||||
import { User } from "..";
|
||||
import { ClientStatus, Status } from "./Status";
|
||||
import { Schema, model, Types, Document } from "mongoose";
|
||||
import toBigInt from "../util/toBigInt";
|
||||
|
||||
export interface Presence {
|
||||
user: User;
|
||||
guild_id?: string;
|
||||
status: Status;
|
||||
activities: Activity[];
|
||||
client_status: ClientStatus;
|
||||
}
|
||||
|
||||
export interface Activity {
|
||||
name: string;
|
||||
type: ActivityType;
|
||||
url?: string;
|
||||
created_at?: Date;
|
||||
timestamps?: {
|
||||
start?: number;
|
||||
end?: number;
|
||||
}[];
|
||||
application_id?: string;
|
||||
details?: string;
|
||||
state?: string;
|
||||
emoji?: {
|
||||
name: string;
|
||||
id?: string;
|
||||
amimated?: boolean;
|
||||
};
|
||||
party?: {
|
||||
id?: string;
|
||||
size?: [number, number];
|
||||
};
|
||||
assets?: {
|
||||
large_image?: string;
|
||||
large_text?: string;
|
||||
small_image?: string;
|
||||
small_text?: string;
|
||||
};
|
||||
secrets?: {
|
||||
join?: string;
|
||||
spectate?: string;
|
||||
match?: string;
|
||||
};
|
||||
instance?: boolean;
|
||||
flags?: bigint;
|
||||
}
|
||||
|
||||
export const ActivitySchema = {
|
||||
name: { type: String, required: true },
|
||||
type: { type: Number, required: true },
|
||||
url: String,
|
||||
created_at: Date,
|
||||
timestamps: [
|
||||
{
|
||||
start: Number,
|
||||
end: Number,
|
||||
},
|
||||
],
|
||||
application_id: String,
|
||||
details: String,
|
||||
state: String,
|
||||
emoji: {
|
||||
name: String,
|
||||
id: String,
|
||||
amimated: Boolean,
|
||||
},
|
||||
party: {
|
||||
id: String,
|
||||
size: [Number, Number],
|
||||
},
|
||||
assets: {
|
||||
large_image: String,
|
||||
large_text: String,
|
||||
small_image: String,
|
||||
small_text: String,
|
||||
},
|
||||
secrets: {
|
||||
join: String,
|
||||
spectate: String,
|
||||
match: String,
|
||||
},
|
||||
instance: Boolean,
|
||||
flags: { type: String, get: toBigInt },
|
||||
};
|
||||
|
||||
export const ActivityBodySchema = {
|
||||
name: String,
|
||||
type: Number,
|
||||
$url: String,
|
||||
$created_at: Date,
|
||||
$timestamps: [
|
||||
{
|
||||
$start: Number,
|
||||
$end: Number,
|
||||
},
|
||||
],
|
||||
$application_id: String,
|
||||
$details: String,
|
||||
$state: String,
|
||||
$emoji: {
|
||||
$name: String,
|
||||
$id: String,
|
||||
$amimated: Boolean,
|
||||
},
|
||||
$party: {
|
||||
$id: String,
|
||||
$size: [Number, Number],
|
||||
},
|
||||
$assets: {
|
||||
$large_image: String,
|
||||
$large_text: String,
|
||||
$small_image: String,
|
||||
$small_text: String,
|
||||
},
|
||||
$secrets: {
|
||||
$join: String,
|
||||
$spectate: String,
|
||||
$match: String,
|
||||
},
|
||||
$instance: Boolean,
|
||||
$flags: BigInt,
|
||||
};
|
||||
|
||||
export enum ActivityType {
|
||||
GAME = 0,
|
||||
STREAMING = 1,
|
||||
LISTENING = 2,
|
||||
CUSTOM = 4,
|
||||
COMPETING = 5,
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
import { Team } from "./Team";
|
||||
|
||||
export interface Application {
|
||||
id: string;
|
||||
name: string;
|
||||
icon: string | null;
|
||||
description: string;
|
||||
rpc_origins: string[] | null;
|
||||
bot_public: boolean;
|
||||
bot_require_code_grant: boolean;
|
||||
terms_of_service_url: string | null;
|
||||
privacy_policy_url: string | null;
|
||||
owner_id: string;
|
||||
summary: string | null;
|
||||
verify_key: string;
|
||||
team: Team | null;
|
||||
guild_id: string; // if this application is a game sold on Discord, this field will be the guild to which it has been linked
|
||||
primary_sku_id: string | null; // if this application is a game sold on Discord, this field will be the id of the "Game SKU" that is created, if exists
|
||||
slug: string | null; // if this application is a game sold on Discord, this field will be the URL slug that links to the store page
|
||||
cover_image: string | null; // the application's default rich presence invite cover image hash
|
||||
flags: number; // the application's public flags
|
||||
}
|
||||
|
||||
export interface ApplicationCommand {
|
||||
id: string;
|
||||
application_id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
options?: ApplicationCommandOption[];
|
||||
}
|
||||
|
||||
export interface ApplicationCommandOption {
|
||||
type: ApplicationCommandOptionType;
|
||||
name: string;
|
||||
description: string;
|
||||
required?: boolean;
|
||||
choices?: ApplicationCommandOptionChoice[];
|
||||
options?: ApplicationCommandOption[];
|
||||
}
|
||||
|
||||
export interface ApplicationCommandOptionChoice {
|
||||
name: string;
|
||||
value: string | number;
|
||||
}
|
||||
|
||||
export enum ApplicationCommandOptionType {
|
||||
SUB_COMMAND = 1,
|
||||
SUB_COMMAND_GROUP = 2,
|
||||
STRING = 3,
|
||||
INTEGER = 4,
|
||||
BOOLEAN = 5,
|
||||
USER = 6,
|
||||
CHANNEL = 7,
|
||||
ROLE = 8,
|
||||
}
|
||||
|
||||
export interface ApplicationCommandInteractionData {
|
||||
id: string;
|
||||
name: string;
|
||||
options?: ApplicationCommandInteractionDataOption[];
|
||||
}
|
||||
|
||||
export interface ApplicationCommandInteractionDataOption {
|
||||
name: string;
|
||||
value?: any;
|
||||
options?: ApplicationCommandInteractionDataOption[];
|
||||
}
|
@ -1,220 +0,0 @@
|
||||
import { Schema, Document, Types } from "mongoose";
|
||||
import db from "../util/Database";
|
||||
import { ChannelPermissionOverwrite } from "./Channel";
|
||||
import { PublicUser } from "./User";
|
||||
|
||||
export interface AuditLogResponse {
|
||||
webhooks: []; // TODO:
|
||||
users: PublicUser[];
|
||||
audit_log_entries: AuditLogEntries[];
|
||||
integrations: []; // TODO:
|
||||
}
|
||||
|
||||
export interface AuditLogEntries {
|
||||
target_id?: string;
|
||||
user_id: string;
|
||||
id: string;
|
||||
action_type: AuditLogEvents;
|
||||
options?: {
|
||||
delete_member_days?: string;
|
||||
members_removed?: string;
|
||||
channel_id?: string;
|
||||
messaged_id?: string;
|
||||
count?: string;
|
||||
id?: string;
|
||||
type?: string;
|
||||
role_name?: string;
|
||||
};
|
||||
changes: AuditLogChange[];
|
||||
reason?: string;
|
||||
}
|
||||
|
||||
export interface AuditLogChange {
|
||||
new_value?: AuditLogChangeValue;
|
||||
old_value?: AuditLogChangeValue;
|
||||
key: string;
|
||||
}
|
||||
|
||||
export interface AuditLogChangeValue {
|
||||
name?: string;
|
||||
description?: string;
|
||||
icon_hash?: string;
|
||||
splash_hash?: string;
|
||||
discovery_splash_hash?: string;
|
||||
banner_hash?: string;
|
||||
owner_id?: string;
|
||||
region?: string;
|
||||
preferred_locale?: string;
|
||||
afk_channel_id?: string;
|
||||
afk_timeout?: number;
|
||||
rules_channel_id?: string;
|
||||
public_updates_channel_id?: string;
|
||||
mfa_level?: number;
|
||||
verification_level?: number;
|
||||
explicit_content_filter?: number;
|
||||
default_message_notifications?: number;
|
||||
vanity_url_code?: string;
|
||||
$add?: {}[];
|
||||
$remove?: {}[];
|
||||
prune_delete_days?: number;
|
||||
widget_enabled?: boolean;
|
||||
widget_channel_id?: string;
|
||||
system_channel_id?: string;
|
||||
position?: number;
|
||||
topic?: string;
|
||||
bitrate?: number;
|
||||
permission_overwrites?: ChannelPermissionOverwrite[];
|
||||
nsfw?: boolean;
|
||||
application_id?: string;
|
||||
rate_limit_per_user?: number;
|
||||
permissions?: string;
|
||||
color?: number;
|
||||
hoist?: boolean;
|
||||
mentionable?: boolean;
|
||||
allow?: string;
|
||||
deny?: string;
|
||||
code?: string;
|
||||
channel_id?: string;
|
||||
inviter_id?: string;
|
||||
max_uses?: number;
|
||||
uses?: number;
|
||||
max_age?: number;
|
||||
temporary?: boolean;
|
||||
deaf?: boolean;
|
||||
mute?: boolean;
|
||||
nick?: string;
|
||||
avatar_hash?: string;
|
||||
id?: string;
|
||||
type?: number;
|
||||
enable_emoticons?: boolean;
|
||||
expire_behavior?: number;
|
||||
expire_grace_period?: number;
|
||||
user_limit?: number;
|
||||
}
|
||||
|
||||
export interface AuditLogEntriesDocument extends Document, AuditLogEntries {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export const AuditLogChanges = {
|
||||
name: String,
|
||||
description: String,
|
||||
icon_hash: String,
|
||||
splash_hash: String,
|
||||
discovery_splash_hash: String,
|
||||
banner_hash: String,
|
||||
owner_id: String,
|
||||
region: String,
|
||||
preferred_locale: String,
|
||||
afk_channel_id: String,
|
||||
afk_timeout: Number,
|
||||
rules_channel_id: String,
|
||||
public_updates_channel_id: String,
|
||||
mfa_level: Number,
|
||||
verification_level: Number,
|
||||
explicit_content_filter: Number,
|
||||
default_message_notifications: Number,
|
||||
vanity_url_code: String,
|
||||
$add: [{}],
|
||||
$remove: [{}],
|
||||
prune_delete_days: Number,
|
||||
widget_enabled: Boolean,
|
||||
widget_channel_id: String,
|
||||
system_channel_id: String,
|
||||
position: Number,
|
||||
topic: String,
|
||||
bitrate: Number,
|
||||
permission_overwrites: [{}],
|
||||
nsfw: Boolean,
|
||||
application_id: String,
|
||||
rate_limit_per_user: Number,
|
||||
permissions: String,
|
||||
color: Number,
|
||||
hoist: Boolean,
|
||||
mentionable: Boolean,
|
||||
allow: String,
|
||||
deny: String,
|
||||
code: String,
|
||||
channel_id: String,
|
||||
inviter_id: String,
|
||||
max_uses: Number,
|
||||
uses: Number,
|
||||
max_age: Number,
|
||||
temporary: Boolean,
|
||||
deaf: Boolean,
|
||||
mute: Boolean,
|
||||
nick: String,
|
||||
avatar_hash: String,
|
||||
id: String,
|
||||
type: Number,
|
||||
enable_emoticons: Boolean,
|
||||
expire_behavior: Number,
|
||||
expire_grace_period: Number,
|
||||
user_limit: Number,
|
||||
};
|
||||
|
||||
export const AuditLogSchema = new Schema({
|
||||
target_id: String,
|
||||
user_id: { type: String, required: true },
|
||||
id: { type: String, required: true },
|
||||
action_type: { type: Number, required: true },
|
||||
options: {
|
||||
delete_member_days: String,
|
||||
members_removed: String,
|
||||
channel_id: String,
|
||||
messaged_id: String,
|
||||
count: String,
|
||||
id: String,
|
||||
type: { type: Number },
|
||||
role_name: String,
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
new_value: AuditLogChanges,
|
||||
old_value: AuditLogChanges,
|
||||
key: String,
|
||||
},
|
||||
],
|
||||
reason: String,
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
export const AuditLogModel = db.model<AuditLogEntries>("AuditLog", AuditLogSchema, "auditlogs");
|
||||
|
||||
export enum AuditLogEvents {
|
||||
GUILD_UPDATE = 1,
|
||||
CHANNEL_CREATE = 10,
|
||||
CHANNEL_UPDATE = 11,
|
||||
CHANNEL_DELETE = 12,
|
||||
CHANNEL_OVERWRITE_CREATE = 13,
|
||||
CHANNEL_OVERWRITE_UPDATE = 14,
|
||||
CHANNEL_OVERWRITE_DELETE = 15,
|
||||
MEMBER_KICK = 20,
|
||||
MEMBER_PRUNE = 21,
|
||||
MEMBER_BAN_ADD = 22,
|
||||
MEMBER_BAN_REMOVE = 23,
|
||||
MEMBER_UPDATE = 24,
|
||||
MEMBER_ROLE_UPDATE = 25,
|
||||
MEMBER_MOVE = 26,
|
||||
MEMBER_DISCONNECT = 27,
|
||||
BOT_ADD = 28,
|
||||
ROLE_CREATE = 30,
|
||||
ROLE_UPDATE = 31,
|
||||
ROLE_DELETE = 32,
|
||||
INVITE_CREATE = 40,
|
||||
INVITE_UPDATE = 41,
|
||||
INVITE_DELETE = 42,
|
||||
WEBHOOK_CREATE = 50,
|
||||
WEBHOOK_UPDATE = 51,
|
||||
WEBHOOK_DELETE = 52,
|
||||
EMOJI_CREATE = 60,
|
||||
EMOJI_UPDATE = 61,
|
||||
EMOJI_DELETE = 62,
|
||||
MESSAGE_DELETE = 72,
|
||||
MESSAGE_BULK_DELETE = 73,
|
||||
MESSAGE_PIN = 74,
|
||||
MESSAGE_UNPIN = 75,
|
||||
INTEGRATION_CREATE = 80,
|
||||
INTEGRATION_UPDATE = 81,
|
||||
INTEGRATION_DELETE = 82,
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
import { Schema, model, Types, Document } from "mongoose";
|
||||
import db from "../util/Database";
|
||||
import { PublicUserProjection, UserModel } from "./User";
|
||||
|
||||
export interface Ban extends Document {
|
||||
user_id: string;
|
||||
guild_id: string;
|
||||
executor_id: string;
|
||||
ip: string;
|
||||
reason?: string;
|
||||
}
|
||||
|
||||
export const BanSchema = new Schema({
|
||||
user_id: { type: String, required: true },
|
||||
guild_id: { type: String, required: true },
|
||||
executor_id: { type: String, required: true },
|
||||
reason: String,
|
||||
ip: String, // ? Should we store this in here, or in the UserModel?
|
||||
});
|
||||
|
||||
BanSchema.virtual("user", {
|
||||
ref: UserModel,
|
||||
localField: "user_id",
|
||||
foreignField: "id",
|
||||
justOne: true,
|
||||
autopopulate: { select: PublicUserProjection },
|
||||
});
|
||||
|
||||
BanSchema.set("removeResponse", ["user_id"]);
|
||||
|
||||
// @ts-ignore
|
||||
export const BanModel = db.model<Ban>("Ban", BanSchema, "bans");
|
@ -1,109 +0,0 @@
|
||||
import { Schema, model, Types, Document } from "mongoose";
|
||||
import db from "../util/Database";
|
||||
import toBigInt from "../util/toBigInt";
|
||||
import { PublicUserProjection, UserModel } from "./User";
|
||||
|
||||
// @ts-ignore
|
||||
export interface AnyChannel extends Channel, DMChannel, TextChannel, VoiceChannel {
|
||||
recipient_ids: null | string[];
|
||||
}
|
||||
|
||||
export interface ChannelDocument extends Document, AnyChannel {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export const ChannelSchema = new Schema({
|
||||
id: String,
|
||||
created_at: { type: Schema.Types.Date, required: true },
|
||||
name: String, // can't be required for dm channels
|
||||
type: { type: Number, required: true },
|
||||
guild_id: String,
|
||||
owner_id: String,
|
||||
parent_id: String,
|
||||
recipient_ids: [String],
|
||||
position: Number,
|
||||
last_message_id: String,
|
||||
last_pin_timestamp: Date,
|
||||
nsfw: Boolean,
|
||||
rate_limit_per_user: Number,
|
||||
topic: String,
|
||||
permission_overwrites: [
|
||||
{
|
||||
allow: { type: String, get: toBigInt },
|
||||
deny: { type: String, get: toBigInt },
|
||||
id: String,
|
||||
type: { type: Number },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
ChannelSchema.virtual("recipients", {
|
||||
ref: UserModel,
|
||||
localField: "recipient_ids",
|
||||
foreignField: "id",
|
||||
justOne: false,
|
||||
autopopulate: { select: PublicUserProjection },
|
||||
});
|
||||
|
||||
ChannelSchema.set("removeResponse", ["recipient_ids"]);
|
||||
|
||||
// @ts-ignore
|
||||
export const ChannelModel = db.model<ChannelDocument>("Channel", ChannelSchema, "channels");
|
||||
|
||||
export interface Channel {
|
||||
id: string;
|
||||
created_at: Date;
|
||||
name: string;
|
||||
type: number;
|
||||
}
|
||||
|
||||
export interface TextBasedChannel {
|
||||
last_message_id?: string;
|
||||
last_pin_timestamp?: number;
|
||||
}
|
||||
|
||||
export interface GuildChannel extends Channel {
|
||||
guild_id: string;
|
||||
position: number;
|
||||
parent_id?: string;
|
||||
permission_overwrites: ChannelPermissionOverwrite[];
|
||||
}
|
||||
|
||||
export interface ChannelPermissionOverwrite {
|
||||
allow: bigint; // for bitfields we use bigints
|
||||
deny: bigint; // for bitfields we use bigints
|
||||
id: string;
|
||||
type: ChannelPermissionOverwriteType;
|
||||
}
|
||||
|
||||
export enum ChannelPermissionOverwriteType {
|
||||
role = 0,
|
||||
member = 1,
|
||||
}
|
||||
|
||||
export interface VoiceChannel extends GuildChannel {
|
||||
video_quality_mode?: number;
|
||||
bitrate?: number;
|
||||
user_limit?: number;
|
||||
}
|
||||
|
||||
export interface TextChannel extends GuildChannel, TextBasedChannel {
|
||||
nsfw: boolean;
|
||||
rate_limit_per_user: number;
|
||||
topic?: string;
|
||||
}
|
||||
// @ts-ignore
|
||||
export interface DMChannel extends Channel, TextBasedChannel {
|
||||
owner_id: string;
|
||||
recipient_ids: string[];
|
||||
}
|
||||
|
||||
export enum ChannelType {
|
||||
GUILD_TEXT = 0, // a text channel within a server
|
||||
DM = 1, // a direct message between users
|
||||
GUILD_VOICE = 2, // a voice channel within a server
|
||||
GROUP_DM = 3, // a direct message between multiple users
|
||||
GUILD_CATEGORY = 4, // an organizational category that contains up to 50 channels
|
||||
GUILD_NEWS = 5, // a channel that users can follow and crosspost into their own server
|
||||
GUILD_STORE = 6, // a channel in which game developers can sell their game on Discord
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
import { Schema, model, Types, Document } from "mongoose";
|
||||
import db from "../util/Database";
|
||||
|
||||
export interface Emoji extends Document {
|
||||
id: string;
|
||||
animated: boolean;
|
||||
available: boolean;
|
||||
guild_id: string;
|
||||
managed: boolean;
|
||||
name: string;
|
||||
require_colons: boolean;
|
||||
url: string;
|
||||
roles: string[]; // roles this emoji is whitelisted to (new discord feature?)
|
||||
}
|
||||
|
||||
export const EmojiSchema = new Schema({
|
||||
id: { type: String, required: true },
|
||||
animated: Boolean,
|
||||
available: Boolean,
|
||||
guild_id: String,
|
||||
managed: Boolean,
|
||||
name: String,
|
||||
require_colons: Boolean,
|
||||
url: String,
|
||||
roles: [String],
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
export const EmojiModel = db.model<Emoji>("Emoji", EmojiSchema, "emojis");
|
@ -1,540 +0,0 @@
|
||||
import { ConnectedAccount, PublicUser, Relationship, User, UserSettings } from "./User";
|
||||
import { DMChannel, Channel } from "./Channel";
|
||||
import { Guild } from "./Guild";
|
||||
import { Member, PublicMember, UserGuildSettings } from "./Member";
|
||||
import { Emoji } from "./Emoji";
|
||||
import { Presence } from "./Activity";
|
||||
import { Role } from "./Role";
|
||||
import { Invite } from "./Invite";
|
||||
import { Message, PartialEmoji } from "./Message";
|
||||
import { VoiceState } from "./VoiceState";
|
||||
import { ApplicationCommand } from "./Application";
|
||||
import { Interaction } from "./Interaction";
|
||||
import { Schema, model, Types, Document } from "mongoose";
|
||||
import db from "../util/Database";
|
||||
|
||||
export interface Event {
|
||||
guild_id?: string;
|
||||
user_id?: string;
|
||||
channel_id?: string;
|
||||
created_at?: Date;
|
||||
event: EVENT;
|
||||
data?: any;
|
||||
}
|
||||
|
||||
export interface EventDocument extends Event, Document {}
|
||||
|
||||
export const EventSchema = new Schema({
|
||||
guild_id: String,
|
||||
user_id: String,
|
||||
channel_id: String,
|
||||
created_at: { type: Date, required: true },
|
||||
event: { type: String, required: true },
|
||||
data: Object,
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
export const EventModel = db.model<EventDocument>("Event", EventSchema, "events");
|
||||
|
||||
// ! Custom Events that shouldn't get sent to the client but processed by the server
|
||||
|
||||
export interface InvalidatedEvent extends Event {
|
||||
event: "INVALIDATED";
|
||||
}
|
||||
|
||||
// ! END Custom Events that shouldn't get sent to the client but processed by the server
|
||||
|
||||
export interface ReadyEventData {
|
||||
v: number;
|
||||
user: PublicUser & {
|
||||
mobile: boolean;
|
||||
desktop: boolean;
|
||||
email: string | null;
|
||||
flags: bigint;
|
||||
mfa_enabled: boolean;
|
||||
nsfw_allowed: boolean;
|
||||
phone: string | null;
|
||||
premium: boolean;
|
||||
premium_type: number;
|
||||
verified: boolean;
|
||||
bot: boolean;
|
||||
};
|
||||
private_channels: DMChannel[]; // this will be empty for bots
|
||||
session_id: string; // resuming
|
||||
guilds: Guild[];
|
||||
analytics_token?: string;
|
||||
connected_accounts?: ConnectedAccount[];
|
||||
consents?: {
|
||||
personalization?: {
|
||||
consented?: boolean;
|
||||
};
|
||||
};
|
||||
country_code?: string; // e.g. DE
|
||||
friend_suggestion_count?: number;
|
||||
geo_ordered_rtc_regions?: string[]; // ["europe","russie","india","us-east","us-central"]
|
||||
experiments?: [number, number, number, number, number][];
|
||||
guild_experiments?: [
|
||||
// ? what are guild_experiments?
|
||||
// this is the structure of it:
|
||||
number,
|
||||
null,
|
||||
number,
|
||||
[[number, { e: number; s: number }[]]],
|
||||
[number, [[number, [number, number]]]],
|
||||
{ b: number; k: bigint[] }[]
|
||||
][];
|
||||
guild_join_requests?: []; // ? what is this? this is new
|
||||
shard?: [number, number];
|
||||
user_settings?: UserSettings;
|
||||
relationships?: Relationship[]; // TODO
|
||||
read_state: {
|
||||
entries: []; // TODO
|
||||
partial: boolean;
|
||||
version: number;
|
||||
};
|
||||
user_guild_settings?: {
|
||||
entries: UserGuildSettings[];
|
||||
version: number;
|
||||
partial: boolean;
|
||||
};
|
||||
application?: {
|
||||
id: string;
|
||||
flags: bigint;
|
||||
};
|
||||
merged_members?: Omit<Member, "settings" | "user">[][];
|
||||
// probably all users who the user is in contact with
|
||||
users?: {
|
||||
avatar: string | null;
|
||||
discriminator: string;
|
||||
id: string;
|
||||
username: string;
|
||||
bot: boolean;
|
||||
public_flags: bigint;
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface ReadyEvent extends Event {
|
||||
event: "READY";
|
||||
data: ReadyEventData;
|
||||
}
|
||||
|
||||
export interface ChannelCreateEvent extends Event {
|
||||
event: "CHANNEL_CREATE";
|
||||
data: Channel;
|
||||
}
|
||||
|
||||
export interface ChannelUpdateEvent extends Event {
|
||||
event: "CHANNEL_UPDATE";
|
||||
data: Channel;
|
||||
}
|
||||
|
||||
export interface ChannelDeleteEvent extends Event {
|
||||
event: "CHANNEL_DELETE";
|
||||
data: Channel;
|
||||
}
|
||||
|
||||
export interface ChannelPinsUpdateEvent extends Event {
|
||||
event: "CHANNEL_PINS_UPDATE";
|
||||
data: {
|
||||
guild_id?: string;
|
||||
channel_id: string;
|
||||
last_pin_timestamp?: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface GuildCreateEvent extends Event {
|
||||
event: "GUILD_CREATE";
|
||||
data: Guild;
|
||||
}
|
||||
|
||||
export interface GuildUpdateEvent extends Event {
|
||||
event: "GUILD_UPDATE";
|
||||
data: Guild;
|
||||
}
|
||||
|
||||
export interface GuildDeleteEvent extends Event {
|
||||
event: "GUILD_DELETE";
|
||||
data: {
|
||||
id: string;
|
||||
unavailable?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface GuildBanAddEvent extends Event {
|
||||
event: "GUILD_BAN_ADD";
|
||||
data: {
|
||||
guild_id: string;
|
||||
user: User;
|
||||
};
|
||||
}
|
||||
|
||||
export interface GuildBanRemoveEvent extends Event {
|
||||
event: "GUILD_BAN_REMOVE";
|
||||
data: {
|
||||
guild_id: string;
|
||||
user: User;
|
||||
};
|
||||
}
|
||||
|
||||
export interface GuildEmojiUpdateEvent extends Event {
|
||||
event: "GUILD_EMOJI_UPDATE";
|
||||
data: {
|
||||
guild_id: string;
|
||||
emojis: Emoji[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface GuildIntegrationUpdateEvent extends Event {
|
||||
event: "GUILD_INTEGRATIONS_UPDATE";
|
||||
data: {
|
||||
guild_id: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface GuildMemberAddEvent extends Event {
|
||||
event: "GUILD_MEMBER_ADD";
|
||||
data: PublicMember & {
|
||||
guild_id: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface GuildMemberRemoveEvent extends Event {
|
||||
event: "GUILD_MEMBER_REMOVE";
|
||||
data: {
|
||||
guild_id: string;
|
||||
user: User;
|
||||
};
|
||||
}
|
||||
|
||||
export interface GuildMemberUpdateEvent extends Event {
|
||||
event: "GUILD_MEMBER_UPDATE";
|
||||
data: {
|
||||
guild_id: string;
|
||||
roles: string[];
|
||||
user: User;
|
||||
nick?: string;
|
||||
joined_at?: Date;
|
||||
premium_since?: number;
|
||||
pending?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface GuildMembersChunkEvent extends Event {
|
||||
event: "GUILD_MEMBERS_CHUNK";
|
||||
data: {
|
||||
guild_id: string;
|
||||
members: PublicMember[];
|
||||
chunk_index: number;
|
||||
chunk_count: number;
|
||||
not_found: string[];
|
||||
presences: Presence[];
|
||||
nonce?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface GuildRoleCreateEvent extends Event {
|
||||
event: "GUILD_ROLE_CREATE";
|
||||
data: {
|
||||
guild_id: string;
|
||||
role: Role;
|
||||
};
|
||||
}
|
||||
|
||||
export interface GuildRoleUpdateEvent extends Event {
|
||||
event: "GUILD_ROLE_UPDATE";
|
||||
data: {
|
||||
guild_id: string;
|
||||
role: Role;
|
||||
};
|
||||
}
|
||||
|
||||
export interface GuildRoleDeleteEvent extends Event {
|
||||
event: "GUILD_ROLE_DELETE";
|
||||
data: {
|
||||
guild_id: string;
|
||||
role_id: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface InviteCreateEvent extends Event {
|
||||
event: "INVITE_CREATE";
|
||||
data: Omit<Invite, "guild" | "channel"> & {
|
||||
channel_id: string;
|
||||
guild_id?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface InviteDeleteEvent extends Event {
|
||||
event: "INVITE_DELETE";
|
||||
data: {
|
||||
channel_id: string;
|
||||
guild_id?: string;
|
||||
code: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type MessagePayload = Omit<Message, "author_id"> & {
|
||||
channel_id: string;
|
||||
guild_id?: string;
|
||||
author: PublicUser;
|
||||
member: PublicMember;
|
||||
mentions: (PublicUser & { member: PublicMember })[];
|
||||
};
|
||||
|
||||
export interface MessageCreateEvent extends Event {
|
||||
event: "MESSAGE_CREATE";
|
||||
data: MessagePayload;
|
||||
}
|
||||
|
||||
export interface MessageUpdateEvent extends Event {
|
||||
event: "MESSAGE_UPDATE";
|
||||
data: MessagePayload;
|
||||
}
|
||||
|
||||
export interface MessageDeleteEvent extends Event {
|
||||
event: "MESSAGE_DELETE";
|
||||
data: {
|
||||
id: string;
|
||||
channel_id: string;
|
||||
guild_id?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface MessageDeleteBulkEvent extends Event {
|
||||
event: "MESSAGE_DELETE_BULK";
|
||||
data: {
|
||||
ids: string[];
|
||||
channel_id: string;
|
||||
guild_id?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface MessageReactionAddEvent extends Event {
|
||||
event: "MESSAGE_REACTION_ADD";
|
||||
data: {
|
||||
user_id: string;
|
||||
channel_id: string;
|
||||
message_id: string;
|
||||
guild_id?: string;
|
||||
member?: PublicMember;
|
||||
emoji: PartialEmoji;
|
||||
};
|
||||
}
|
||||
|
||||
export interface MessageReactionRemoveEvent extends Event {
|
||||
event: "MESSAGE_REACTION_REMOVE";
|
||||
data: {
|
||||
user_id: string;
|
||||
channel_id: string;
|
||||
message_id: string;
|
||||
guild_id?: string;
|
||||
emoji: PartialEmoji;
|
||||
};
|
||||
}
|
||||
|
||||
export interface MessageReactionRemoveAllEvent extends Event {
|
||||
event: "MESSAGE_REACTION_REMOVE_ALL";
|
||||
data: {
|
||||
channel_id: string;
|
||||
message_id: string;
|
||||
guild_id?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface MessageReactionRemoveEmojiEvent extends Event {
|
||||
event: "MESSAGE_REACTION_REMOVE_EMOJI";
|
||||
data: {
|
||||
channel_id: string;
|
||||
message_id: string;
|
||||
guild_id?: string;
|
||||
emoji: PartialEmoji;
|
||||
};
|
||||
}
|
||||
|
||||
export interface PresenceUpdateEvent extends Event {
|
||||
event: "PRESENCE_UPDATE";
|
||||
data: Presence;
|
||||
}
|
||||
|
||||
export interface TypingStartEvent extends Event {
|
||||
event: "TYPING_START";
|
||||
data: {
|
||||
channel_id: string;
|
||||
user_id: string;
|
||||
timestamp: number;
|
||||
guild_id?: string;
|
||||
member?: PublicMember;
|
||||
};
|
||||
}
|
||||
|
||||
export interface UserUpdateEvent extends Event {
|
||||
event: "USER_UPDATE";
|
||||
data: User;
|
||||
}
|
||||
|
||||
export interface VoiceStateUpdateEvent extends Event {
|
||||
event: "VOICE_STATE_UPDATE";
|
||||
data: VoiceState & {
|
||||
member: PublicMember;
|
||||
};
|
||||
}
|
||||
|
||||
export interface VoiceServerUpdateEvent extends Event {
|
||||
event: "VOICE_SERVER_UPDATE";
|
||||
data: {
|
||||
token: string;
|
||||
guild_id: string;
|
||||
endpoint: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface WebhooksUpdateEvent extends Event {
|
||||
event: "WEBHOOKS_UPDATE";
|
||||
data: {
|
||||
guild_id: string;
|
||||
channel_id: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type ApplicationCommandPayload = ApplicationCommand & {
|
||||
guild_id: string;
|
||||
};
|
||||
|
||||
export interface ApplicationCommandCreateEvent extends Event {
|
||||
event: "APPLICATION_COMMAND_CREATE";
|
||||
data: ApplicationCommandPayload;
|
||||
}
|
||||
|
||||
export interface ApplicationCommandUpdateEvent extends Event {
|
||||
event: "APPLICATION_COMMAND_UPDATE";
|
||||
data: ApplicationCommandPayload;
|
||||
}
|
||||
|
||||
export interface ApplicationCommandDeleteEvent extends Event {
|
||||
event: "APPLICATION_COMMAND_DELETE";
|
||||
data: ApplicationCommandPayload;
|
||||
}
|
||||
|
||||
export interface InteractionCreateEvent extends Event {
|
||||
event: "INTERACTION_CREATE";
|
||||
data: Interaction;
|
||||
}
|
||||
|
||||
export interface MessageAckEvent extends Event {
|
||||
event: "MESSAGE_ACK";
|
||||
data: {
|
||||
channel_id: string;
|
||||
message_id: string;
|
||||
version?: number;
|
||||
manual?: boolean;
|
||||
mention_count?: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface RelationshipAddEvent extends Event {
|
||||
event: "RELATIONSHIP_ADD";
|
||||
data: Relationship & {
|
||||
should_notify?: boolean;
|
||||
user: PublicUser;
|
||||
};
|
||||
}
|
||||
|
||||
export interface RelationshipRemoveEvent extends Event {
|
||||
event: "RELATIONSHIP_REMOVE";
|
||||
data: Omit<Relationship, "nickname">;
|
||||
}
|
||||
|
||||
// located in collection events
|
||||
|
||||
export enum EVENTEnum {
|
||||
Ready = "READY",
|
||||
ChannelCreate = "CHANNEL_CREATE",
|
||||
ChannelUpdate = "CHANNEL_UPDATE",
|
||||
ChannelDelete = "CHANNEL_DELETE",
|
||||
ChannelPinsUpdate = "CHANNEL_PINS_UPDATE",
|
||||
GuildCreate = "GUILD_CREATE",
|
||||
GuildUpdate = "GUILD_UPDATE",
|
||||
GuildDelete = "GUILD_DELETE",
|
||||
GuildBanAdd = "GUILD_BAN_ADD",
|
||||
GuildBanRemove = "GUILD_BAN_REMOVE",
|
||||
GuildEmojUpdate = "GUILD_EMOJI_UPDATE",
|
||||
GuildIntegrationsUpdate = "GUILD_INTEGRATIONS_UPDATE",
|
||||
GuildMemberAdd = "GUILD_MEMBER_ADD",
|
||||
GuildMemberRempve = "GUILD_MEMBER_REMOVE",
|
||||
GuildMemberUpdate = "GUILD_MEMBER_UPDATE",
|
||||
GuildMemberSpeaking = "GUILD_MEMBER_SPEAKING",
|
||||
GuildMembersChunk = "GUILD_MEMBERS_CHUNK",
|
||||
GuildRoleCreate = "GUILD_ROLE_CREATE",
|
||||
GuildRoleDelete = "GUILD_ROLE_DELETE",
|
||||
GuildRoleUpdate = "GUILD_ROLE_UPDATE",
|
||||
InviteCreate = "INVITE_CREATE",
|
||||
InviteDelete = "INVITE_DELETE",
|
||||
MessageCreate = "MESSAGE_CREATE",
|
||||
MessageUpdate = "MESSAGE_UPDATE",
|
||||
MessageDelete = "MESSAGE_DELETE",
|
||||
MessageDeleteBulk = "MESSAGE_DELETE_BULK",
|
||||
MessageReactionAdd = "MESSAGE_REACTION_ADD",
|
||||
MessageReactionRemove = "MESSAGE_REACTION_REMOVE",
|
||||
MessageReactionRemoveAll = "MESSAGE_REACTION_REMOVE_ALL",
|
||||
MessageReactionRemoveEmoji = "MESSAGE_REACTION_REMOVE_EMOJI",
|
||||
PresenceUpdate = "PRESENCE_UPDATE",
|
||||
TypingStart = "TYPING_START",
|
||||
UserUpdate = "USER_UPDATE",
|
||||
WebhooksUpdate = "WEBHOOKS_UPDATE",
|
||||
InteractionCreate = "INTERACTION_CREATE",
|
||||
VoiceStateUpdate = "VOICE_STATE_UPDATE",
|
||||
VoiceServerUpdate = "VOICE_SERVER_UPDATE",
|
||||
ApplicationCommandCreate = "APPLICATION_COMMAND_CREATE",
|
||||
ApplicationCommandUpdate = "APPLICATION_COMMAND_UPDATE",
|
||||
ApplicationCommandDelete = "APPLICATION_COMMAND_DELETE",
|
||||
}
|
||||
|
||||
export type EVENT =
|
||||
| "READY"
|
||||
| "CHANNEL_CREATE"
|
||||
| "CHANNEL_UPDATE"
|
||||
| "CHANNEL_DELETE"
|
||||
| "CHANNEL_PINS_UPDATE"
|
||||
| "GUILD_CREATE"
|
||||
| "GUILD_UPDATE"
|
||||
| "GUILD_DELETE"
|
||||
| "GUILD_BAN_ADD"
|
||||
| "GUILD_BAN_REMOVE"
|
||||
| "GUILD_EMOJI_UPDATE"
|
||||
| "GUILD_INTEGRATIONS_UPDATE"
|
||||
| "GUILD_MEMBER_ADD"
|
||||
| "GUILD_MEMBER_REMOVE"
|
||||
| "GUILD_MEMBER_UPDATE"
|
||||
| "GUILD_MEMBER_SPEAKING"
|
||||
| "GUILD_MEMBERS_CHUNK"
|
||||
| "GUILD_ROLE_CREATE"
|
||||
| "GUILD_ROLE_DELETE"
|
||||
| "GUILD_ROLE_UPDATE"
|
||||
| "INVITE_CREATE"
|
||||
| "INVITE_DELETE"
|
||||
| "MESSAGE_CREATE"
|
||||
| "MESSAGE_UPDATE"
|
||||
| "MESSAGE_DELETE"
|
||||
| "MESSAGE_DELETE_BULK"
|
||||
| "MESSAGE_REACTION_ADD"
|
||||
// TODO: add a new event: bulk add reaction:
|
||||
// | "MESSAGE_REACTION_BULK_ADD"
|
||||
| "MESSAGE_REACTION_REMOVE"
|
||||
| "MESSAGE_REACTION_REMOVE_ALL"
|
||||
| "MESSAGE_REACTION_REMOVE_EMOJI"
|
||||
| "PRESENCE_UPDATE"
|
||||
| "TYPING_START"
|
||||
| "USER_UPDATE"
|
||||
| "WEBHOOKS_UPDATE"
|
||||
| "INTERACTION_CREATE"
|
||||
| "VOICE_STATE_UPDATE"
|
||||
| "VOICE_SERVER_UPDATE"
|
||||
| "APPLICATION_COMMAND_CREATE"
|
||||
| "APPLICATION_COMMAND_UPDATE"
|
||||
| "APPLICATION_COMMAND_DELETE"
|
||||
| "MESSAGE_ACK"
|
||||
| "RELATIONSHIP_ADD"
|
||||
| "RELATIONSHIP_REMOVE"
|
||||
| CUSTOMEVENTS;
|
||||
|
||||
export type CUSTOMEVENTS = "INVALIDATED";
|
@ -1,161 +0,0 @@
|
||||
import { Schema, model, Types, Document } from "mongoose";
|
||||
import db from "../util/Database";
|
||||
import { ChannelModel } from "./Channel";
|
||||
import { EmojiModel } from "./Emoji";
|
||||
import { MemberModel } from "./Member";
|
||||
import { RoleModel } from "./Role";
|
||||
|
||||
export interface GuildDocument extends Document, Guild {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface Guild {
|
||||
id: string;
|
||||
afk_channel_id?: string;
|
||||
afk_timeout?: number;
|
||||
application_id?: string;
|
||||
banner?: string;
|
||||
default_message_notifications?: number;
|
||||
description?: string;
|
||||
discovery_splash?: string;
|
||||
explicit_content_filter?: number;
|
||||
features: string[];
|
||||
icon?: string;
|
||||
large?: boolean;
|
||||
max_members?: number; // e.g. default 100.000
|
||||
max_presences?: number;
|
||||
max_video_channel_users?: number; // ? default: 25, is this max 25 streaming or watching
|
||||
member_count?: number;
|
||||
presence_count?: number; // users online
|
||||
// members?: Member[]; // * Members are stored in a seperate collection
|
||||
// roles: Role[]; // * Role are stored in a seperate collection
|
||||
// channels: GuildChannel[]; // * Channels are stored in a seperate collection
|
||||
// emojis: Emoji[]; // * Emojis are stored in a seperate collection
|
||||
// voice_states: []; // * voice_states are stored in a seperate collection
|
||||
//TODO:
|
||||
presences?: object[];
|
||||
mfa_level?: number;
|
||||
name: string;
|
||||
owner_id: string;
|
||||
preferred_locale?: string; // only community guilds can choose this
|
||||
premium_subscription_count?: number;
|
||||
premium_tier?: number; // nitro boost level
|
||||
public_updates_channel_id?: string;
|
||||
region?: string;
|
||||
rules_channel_id?: string;
|
||||
splash?: string;
|
||||
system_channel_flags?: number;
|
||||
system_channel_id?: string;
|
||||
unavailable?: boolean;
|
||||
vanity_url?: {
|
||||
code: string;
|
||||
uses: number;
|
||||
};
|
||||
verification_level?: number;
|
||||
welcome_screen: {
|
||||
enabled: boolean;
|
||||
description: string;
|
||||
welcome_channels: {
|
||||
description: string;
|
||||
emoji_id?: string;
|
||||
emoji_name: string;
|
||||
channel_id: string }[];
|
||||
};
|
||||
widget_channel_id?: string;
|
||||
widget_enabled?: boolean;
|
||||
}
|
||||
|
||||
export const GuildSchema = new Schema({
|
||||
id: { type: String, required: true },
|
||||
afk_channel_id: String,
|
||||
afk_timeout: Number,
|
||||
application_id: String,
|
||||
banner: String,
|
||||
default_message_notifications: Number,
|
||||
description: String,
|
||||
discovery_splash: String,
|
||||
explicit_content_filter: Number,
|
||||
features: { type: [String], default: [] },
|
||||
icon: String,
|
||||
large: Boolean,
|
||||
max_members: { type: Number, default: 100000 },
|
||||
max_presences: Number,
|
||||
max_video_channel_users: { type: Number, default: 25 },
|
||||
member_count: Number,
|
||||
presences: { type: [Object], default: [] },
|
||||
presence_count: Number,
|
||||
mfa_level: Number,
|
||||
name: { type: String, required: true },
|
||||
owner_id: { type: String, required: true },
|
||||
preferred_locale: String,
|
||||
premium_subscription_count: Number,
|
||||
premium_tier: Number,
|
||||
public_updates_channel_id: String,
|
||||
region: String,
|
||||
rules_channel_id: String,
|
||||
splash: String,
|
||||
system_channel_flags: Number,
|
||||
system_channel_id: String,
|
||||
unavailable: Boolean,
|
||||
vanity_url: {
|
||||
code: String,
|
||||
uses: Number
|
||||
},
|
||||
verification_level: Number,
|
||||
voice_states: { type: [Object], default: [] },
|
||||
welcome_screen: {
|
||||
enabled: Boolean,
|
||||
description: String,
|
||||
welcome_channels: [{
|
||||
description: String,
|
||||
emoji_id: String,
|
||||
emoji_name: String,
|
||||
channel_id: String }],
|
||||
},
|
||||
widget_channel_id: String,
|
||||
widget_enabled: Boolean,
|
||||
});
|
||||
|
||||
GuildSchema.virtual("channels", {
|
||||
ref: ChannelModel,
|
||||
localField: "id",
|
||||
foreignField: "guild_id",
|
||||
justOne: false,
|
||||
autopopulate: true,
|
||||
});
|
||||
|
||||
GuildSchema.virtual("roles", {
|
||||
ref: RoleModel,
|
||||
localField: "id",
|
||||
foreignField: "guild_id",
|
||||
justOne: false,
|
||||
autopopulate: true,
|
||||
});
|
||||
|
||||
// nested populate is needed for member users: https://gist.github.com/yangsu/5312204
|
||||
GuildSchema.virtual("members", {
|
||||
ref: MemberModel,
|
||||
localField: "id",
|
||||
foreignField: "guild_id",
|
||||
justOne: false,
|
||||
});
|
||||
|
||||
GuildSchema.virtual("emojis", {
|
||||
ref: EmojiModel,
|
||||
localField: "id",
|
||||
foreignField: "guild_id",
|
||||
justOne: false,
|
||||
autopopulate: true,
|
||||
});
|
||||
|
||||
GuildSchema.virtual("joined_at", {
|
||||
ref: MemberModel,
|
||||
localField: "id",
|
||||
foreignField: "guild_id",
|
||||
justOne: true,
|
||||
}).get((member: any, virtual: any, doc: any) => {
|
||||
return member?.joined_at;
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
export const GuildModel = db.model<GuildDocument>("Guild", GuildSchema, "guilds");
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user