From ccc774168a0612c6892b7862141e58b28b029aec Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Mon, 21 Aug 2023 23:28:36 +1000 Subject: [PATCH 01/20] Close #1091 --- src/gateway/opcodes/Identify.ts | 58 ++++++++++++++++----------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/gateway/opcodes/Identify.ts b/src/gateway/opcodes/Identify.ts index 7610901a..0f5469cf 100644 --- a/src/gateway/opcodes/Identify.ts +++ b/src/gateway/opcodes/Identify.ts @@ -17,43 +17,43 @@ */ import { - WebSocket, - Payload, - setupListener, - Capabilities, CLOSECODES, + Capabilities, OPCODES, + Payload, Send, + WebSocket, + setupListener, } from "@spacebar/gateway"; import { - checkToken, + Application, + Config, + DMChannel, + DefaultUserGuildSettings, + EVENTEnum, + Guild, + GuildOrUnavailable, + IdentifySchema, Intents, Member, - ReadyEventData, - Session, - EVENTEnum, - Config, - PublicUser, - PrivateUserProjection, - ReadState, - Application, - emitEvent, - SessionsReplace, - PrivateSessionProjection, MemberPrivateProjection, - PresenceUpdateEvent, - IdentifySchema, - DefaultUserGuildSettings, - ReadyGuildDTO, - Guild, - PublicUserProjection, - ReadyUserGuildSettingsEntries, - UserSettings, - Permissions, - DMChannel, - GuildOrUnavailable, - Recipient, OPCodes, + Permissions, + PresenceUpdateEvent, + PrivateSessionProjection, + PrivateUserProjection, + PublicUser, + PublicUserProjection, + ReadState, + ReadyEventData, + ReadyGuildDTO, + ReadyUserGuildSettingsEntries, + Recipient, + Session, + SessionsReplace, + UserSettings, + checkToken, + emitEvent, } from "@spacebar/util"; import { check } from "./instanceOf"; @@ -332,7 +332,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { // TODO how is active determined? // in our lazy request impl, we just pick the 'most relevant' session active: x.session_id == session.session_id, - activities: x.activities, + activities: x.activities ?? [], client_info: x.client_info, // TODO: what does all mean? session_id: x.session_id == session.session_id ? "all" : x.session_id, From 8a7ee8c8a93bff0e90f88105932f0015eeedbbaa Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Mon, 21 Aug 2023 23:57:44 +1000 Subject: [PATCH 02/20] what the fuck is session_id: "all"??? --- src/gateway/opcodes/Identify.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/gateway/opcodes/Identify.ts b/src/gateway/opcodes/Identify.ts index 0f5469cf..e097e44c 100644 --- a/src/gateway/opcodes/Identify.ts +++ b/src/gateway/opcodes/Identify.ts @@ -334,8 +334,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { active: x.session_id == session.session_id, activities: x.activities ?? [], client_info: x.client_info, - // TODO: what does all mean? - session_id: x.session_id == session.session_id ? "all" : x.session_id, + session_id: x.session_id, // TODO: discord.com sends 'all', what is that??? status: x.status, })); From d158b11421c43303040b4022bda46a4185cd83c5 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Fri, 25 Aug 2023 00:03:03 +1000 Subject: [PATCH 03/20] Update build.yml --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e3bcc81f..d5ce87e2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,9 +2,9 @@ name: Build on: push: - branches: [ "**" ] + branches: [ "master" ] pull_request: - branches: [ "**" ] + branches: [ "master" ] jobs: build: @@ -25,4 +25,4 @@ jobs: cache: 'npm' - run: npm ci - run: npm run build --if-present - - run: npm run test --if-present \ No newline at end of file + - run: npm run test --if-present From 3a561b5cf605e03a2a4222edbc3e1dbc496da60e Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Fri, 25 Aug 2023 00:03:15 +1000 Subject: [PATCH 04/20] Update style.yml --- .github/workflows/style.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index 4fd62bae..8b18f6e6 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -2,9 +2,9 @@ name: Style on: push: - branches: [ "**" ] + branches: [ "master" ] pull_request: - branches: [ "**" ] + branches: [ "master" ] jobs: build: @@ -25,4 +25,4 @@ jobs: cache: 'npm' - run: npm i --only=dev - run: npx eslint . - - run: npx prettier --check . \ No newline at end of file + - run: npx prettier --check . From 3498ffdc013e82efec16aa7b985f1e3d08bdfe99 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Sun, 27 Aug 2023 16:54:54 +1000 Subject: [PATCH 05/20] prevent put /guilds/id/members/id for others until we have oauth2 scopes impled --- src/api/routes/guilds/#guild_id/members/#member_id/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/api/routes/guilds/#guild_id/members/#member_id/index.ts b/src/api/routes/guilds/#guild_id/members/#member_id/index.ts index cafb922e..c168f2dc 100644 --- a/src/api/routes/guilds/#guild_id/members/#member_id/index.ts +++ b/src/api/routes/guilds/#guild_id/members/#member_id/index.ts @@ -18,6 +18,7 @@ import { route } from "@spacebar/api"; import { + DiscordApiErrors, emitEvent, Emoji, getPermission, @@ -198,7 +199,9 @@ router.put( member_id = req.user_id; rights.hasThrow("JOIN_GUILDS"); } else { - // TODO: join others by controller + // TODO: check oauth2 scope + + throw DiscordApiErrors.MISSING_REQUIRED_OAUTH2_SCOPE; } const guild = await Guild.findOneOrFail({ From c311edc99c4dfc2a275ab99b887769660c29bbf0 Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Sun, 27 Aug 2023 20:16:49 -0400 Subject: [PATCH 06/20] make guild voice a text based channel --- src/util/entities/Channel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts index 19952bc2..6268d735 100644 --- a/src/util/entities/Channel.ts +++ b/src/util/entities/Channel.ts @@ -506,7 +506,6 @@ export interface DMChannel extends Omit { export function isTextChannel(type: ChannelType): boolean { switch (type) { case ChannelType.GUILD_STORE: - case ChannelType.GUILD_VOICE: case ChannelType.GUILD_STAGE_VOICE: case ChannelType.GUILD_CATEGORY: case ChannelType.GUILD_FORUM: @@ -515,6 +514,7 @@ export function isTextChannel(type: ChannelType): boolean { case ChannelType.DM: case ChannelType.GROUP_DM: case ChannelType.GUILD_NEWS: + case ChannelType.GUILD_VOICE: case ChannelType.GUILD_NEWS_THREAD: case ChannelType.GUILD_PUBLIC_THREAD: case ChannelType.GUILD_PRIVATE_THREAD: From ed7fd34f46ffd1322f7d0e6ea81e4612afb0ec4a Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Sat, 2 Sep 2023 01:01:58 +1000 Subject: [PATCH 07/20] DB_LOGGING env var --- src/util/util/Database.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/util/util/Database.ts b/src/util/util/Database.ts index a6b24b3e..3a45eea0 100644 --- a/src/util/util/Database.ts +++ b/src/util/util/Database.ts @@ -16,12 +16,12 @@ along with this program. If not, see . */ -import { DataSource } from "typeorm"; -import { yellow, green, red } from "picocolors"; -import { Migration } from "../entities/Migration"; -import { ConfigEntity } from "../entities/Config"; import { config } from "dotenv"; import path from "path"; +import { green, red, yellow } from "picocolors"; +import { DataSource } from "typeorm"; +import { ConfigEntity } from "../entities/Config"; +import { Migration } from "../entities/Migration"; // UUID extension option is only supported with postgres // We want to generate all id's with Snowflakes that's why we have our own BaseEntity class @@ -50,7 +50,7 @@ const DataSourceOptions = new DataSource({ database: isSqlite ? dbConnectionString : undefined, entities: [path.join(__dirname, "..", "entities", "*.js")], synchronize: !!process.env.DB_SYNC, - logging: false, + logging: !!process.env.DB_LOGGING, bigNumberStrings: false, supportBigNumbers: true, name: "default", @@ -129,7 +129,7 @@ export async function initDatabase(): Promise { return dbConnection; } -export { dbConnection, DataSourceOptions, DatabaseType }; +export { DataSourceOptions, DatabaseType, dbConnection }; export async function closeDatabase() { await dbConnection?.destroy(); From 2f48212e6e6813f90eb13cf8ed79e0ebb3440b31 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Sat, 2 Sep 2023 02:21:42 +1000 Subject: [PATCH 08/20] typeorm inverse relations of guild relations --- src/util/entities/Channel.ts | 5 +++-- src/util/entities/Emoji.ts | 2 +- src/util/entities/Invite.ts | 2 +- src/util/entities/Member.ts | 1 + src/util/entities/Role.ts | 4 ++-- src/util/entities/Sticker.ts | 4 ++-- src/util/entities/VoiceState.ts | 4 ++-- 7 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts index 6268d735..9f7041d4 100644 --- a/src/util/entities/Channel.ts +++ b/src/util/entities/Channel.ts @@ -97,10 +97,11 @@ export class Channel extends BaseClass { guild_id?: string; @JoinColumn({ name: "guild_id" }) - @ManyToOne(() => Guild, { + @ManyToOne(() => Guild, (guild) => guild.channels, { onDelete: "CASCADE", + nullable: true, }) - guild: Guild; + guild?: Guild; @Column({ nullable: true }) @RelationId((channel: Channel) => channel.parent) diff --git a/src/util/entities/Emoji.ts b/src/util/entities/Emoji.ts index 0bc2f423..4d851698 100644 --- a/src/util/entities/Emoji.ts +++ b/src/util/entities/Emoji.ts @@ -33,7 +33,7 @@ export class Emoji extends BaseClass { guild_id: string; @JoinColumn({ name: "guild_id" }) - @ManyToOne(() => Guild, { + @ManyToOne(() => Guild, (guild) => guild.emojis, { onDelete: "CASCADE", }) guild: Guild; diff --git a/src/util/entities/Invite.ts b/src/util/entities/Invite.ts index 7970c4f0..f7e54fbe 100644 --- a/src/util/entities/Invite.ts +++ b/src/util/entities/Invite.ts @@ -53,7 +53,7 @@ export class Invite extends BaseClassWithoutId { guild_id: string; @JoinColumn({ name: "guild_id" }) - @ManyToOne(() => Guild, { + @ManyToOne(() => Guild, (guild) => guild.invites, { onDelete: "CASCADE", }) guild: Guild; diff --git a/src/util/entities/Member.ts b/src/util/entities/Member.ts index d305e4f5..0535313e 100644 --- a/src/util/entities/Member.ts +++ b/src/util/entities/Member.ts @@ -327,6 +327,7 @@ export class Member extends BaseClassWithoutId { id: guild_id, }, relations: PublicGuildRelations, + relationLoadStrategy: "query", }); const memberCount = await Member.count({ where: { guild_id } }); diff --git a/src/util/entities/Role.ts b/src/util/entities/Role.ts index 9a601f31..e8e5feda 100644 --- a/src/util/entities/Role.ts +++ b/src/util/entities/Role.ts @@ -23,12 +23,12 @@ import { Guild } from "./Guild"; @Entity("roles") export class Role extends BaseClass { - @Column({ nullable: true }) + @Column() @RelationId((role: Role) => role.guild) guild_id: string; @JoinColumn({ name: "guild_id" }) - @ManyToOne(() => Guild, { + @ManyToOne(() => Guild, (guild) => guild.roles, { onDelete: "CASCADE", }) guild: Guild; diff --git a/src/util/entities/Sticker.ts b/src/util/entities/Sticker.ts index cd07e65a..e9294f92 100644 --- a/src/util/entities/Sticker.ts +++ b/src/util/entities/Sticker.ts @@ -17,9 +17,9 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { User } from "./User"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; +import { User } from "./User"; export enum StickerType { STANDARD = 1, @@ -62,7 +62,7 @@ export class Sticker extends BaseClass { guild_id?: string; @JoinColumn({ name: "guild_id" }) - @ManyToOne(() => Guild, { + @ManyToOne(() => Guild, (guild) => guild.stickers, { onDelete: "CASCADE", }) guild?: Guild; diff --git a/src/util/entities/VoiceState.ts b/src/util/entities/VoiceState.ts index b291c4d3..84b0ca71 100644 --- a/src/util/entities/VoiceState.ts +++ b/src/util/entities/VoiceState.ts @@ -20,8 +20,8 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Channel } from "./Channel"; import { Guild } from "./Guild"; -import { User } from "./User"; import { Member } from "./Member"; +import { User } from "./User"; //https://gist.github.com/vassjozsef/e482c65df6ee1facaace8b3c9ff66145#file-voice_state-ex @Entity("voice_states") @@ -31,7 +31,7 @@ export class VoiceState extends BaseClass { guild_id: string; @JoinColumn({ name: "guild_id" }) - @ManyToOne(() => Guild, { + @ManyToOne(() => Guild, (guild) => guild.voice_states, { onDelete: "CASCADE", }) guild?: Guild; From eebd61b19d9d21c32685e72552748874c10c8dfb Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Sat, 2 Sep 2023 14:10:32 +1000 Subject: [PATCH 09/20] update sentry --- package-lock.json | 122 +++++++++++++++++++++------------------- package.json | 5 +- src/util/util/Sentry.ts | 35 ++++++++---- 3 files changed, 90 insertions(+), 72 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0576c589..aabad644 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,8 @@ "license": "AGPL-3.0-only", "dependencies": { "@aws-sdk/client-s3": "^3.385.0", - "@sentry/integrations": "^7.61.1", - "@sentry/node": "^7.61.1", - "@sentry/tracing": "^7.61.1", + "@sentry/integrations": "^7.66.0", + "@sentry/node": "^7.66.0", "ajv": "8.6.2", "ajv-formats": "2.1.1", "amqplib": "^0.10.3", @@ -1245,40 +1244,13 @@ "node": "6.* || 8.* || >=10.*" } }, - "node_modules/@sentry-internal/tracing": { - "version": "7.63.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.63.0.tgz", - "integrity": "sha512-Fxpc53p6NGvLSURg3iRvZA0k10K9yfeVhtczvJnpX30POBuV41wxpkLHkb68fjksirjEma1K3Ut1iLOEEDpPQg==", - "dependencies": { - "@sentry/core": "7.63.0", - "@sentry/types": "7.63.0", - "@sentry/utils": "7.63.0", - "tslib": "^2.4.1 || ^1.9.3" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@sentry/core": { - "version": "7.63.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.63.0.tgz", - "integrity": "sha512-13Ljiq8hv6ieCkO+Am99/PljYJO5ynKT/hRQrWgGy9IIEgUr8sV3fW+1W6K4/3MCeOJou0HsiGBjOD1mASItVg==", - "dependencies": { - "@sentry/types": "7.63.0", - "@sentry/utils": "7.63.0", - "tslib": "^2.4.1 || ^1.9.3" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@sentry/integrations": { - "version": "7.63.0", - "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.63.0.tgz", - "integrity": "sha512-+P8GNqFZNH/yS/KPbvUfUDERneoRNUrqp9ayvvp8aq4cTtrBdM72CYgI21oG6cti42SSM1VDLYZomTV3ElPzSg==", + "version": "7.66.0", + "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.66.0.tgz", + "integrity": "sha512-2PNEnihG9e9Rjbz205+A4BYtFcS2XdgwsN6obAU6Yir7VIbskwZXxx87lKZuz6S53sOWPHleC7uvUBjL+Q6vYg==", "dependencies": { - "@sentry/types": "7.63.0", - "@sentry/utils": "7.63.0", + "@sentry/types": "7.66.0", + "@sentry/utils": "7.66.0", "localforage": "^1.8.1", "tslib": "^2.4.1 || ^1.9.3" }, @@ -1286,15 +1258,35 @@ "node": ">=8" } }, - "node_modules/@sentry/node": { - "version": "7.63.0", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.63.0.tgz", - "integrity": "sha512-tSMyfQNbfjX1w8vJDZtvWeaD4QQ/Z4zVW/TLXfL/JZFIIksPgDZmqLdF+NJS4bSGTU5JiHiUh4pYhME4mHgNBQ==", + "node_modules/@sentry/integrations/node_modules/@sentry/types": { + "version": "7.66.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.66.0.tgz", + "integrity": "sha512-uUMSoSiar6JhuD8p7ON/Ddp4JYvrVd2RpwXJRPH1A4H4Bd4DVt1mKJy1OLG6HdeQv39XyhB1lPZckKJg4tATPw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/integrations/node_modules/@sentry/utils": { + "version": "7.66.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.66.0.tgz", + "integrity": "sha512-9GYUVgXjK66uXXcLXVMXVzlptqMtq1eJENCuDeezQiEFrNA71KkLDg00wESp+LL+bl3wpVTBApArpbF6UEG5hQ==", "dependencies": { - "@sentry-internal/tracing": "7.63.0", - "@sentry/core": "7.63.0", - "@sentry/types": "7.63.0", - "@sentry/utils": "7.63.0", + "@sentry/types": "7.66.0", + "tslib": "^2.4.1 || ^1.9.3" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/node": { + "version": "7.66.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.66.0.tgz", + "integrity": "sha512-PxqIqLr4Sh5xcDfECiBQ4PuZ7v8yTgLhaRkruWrZPYxQrcJFPkwbFkw/IskzVnhT2VwXUmeWEIlRMQKBJ0t83A==", + "dependencies": { + "@sentry-internal/tracing": "7.66.0", + "@sentry/core": "7.66.0", + "@sentry/types": "7.66.0", + "@sentry/utils": "7.66.0", "cookie": "^0.4.1", "https-proxy-agent": "^5.0.0", "lru_map": "^0.3.3", @@ -1304,31 +1296,47 @@ "node": ">=8" } }, - "node_modules/@sentry/tracing": { - "version": "7.63.0", - "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.63.0.tgz", - "integrity": "sha512-91gjqM/3CD6XdN1JVSLnUTD7HAI77NodP48+FZ2kgRkNmD2jojJBWsTC9NHG4UEO0PppjjwDPPJR1iHwybaO8g==", + "node_modules/@sentry/node/node_modules/@sentry-internal/tracing": { + "version": "7.66.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.66.0.tgz", + "integrity": "sha512-3vCgC2hC3T45pn53yTDVcRpHoJTBxelDPPZVsipAbZnoOVPkj7n6dNfDhj3I3kwWCBPahPkXmE+R4xViR8VqJg==", "dependencies": { - "@sentry-internal/tracing": "7.63.0" + "@sentry/core": "7.66.0", + "@sentry/types": "7.66.0", + "@sentry/utils": "7.66.0", + "tslib": "^2.4.1 || ^1.9.3" }, "engines": { "node": ">=8" } }, - "node_modules/@sentry/types": { - "version": "7.63.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.63.0.tgz", - "integrity": "sha512-pZNwJVW7RqNLGuTUAhoygt0c9zmc0js10eANAz0MstygJRhQI1tqPDuiELVdujPrbeL+IFKF+7NvRDAydR2Niw==", + "node_modules/@sentry/node/node_modules/@sentry/core": { + "version": "7.66.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.66.0.tgz", + "integrity": "sha512-WMAEPN86NeCJ1IT48Lqiz4MS5gdDjBwP4M63XP4msZn9aujSf2Qb6My5uT87AJr9zBtgk8MyJsuHr35F0P3q1w==", + "dependencies": { + "@sentry/types": "7.66.0", + "@sentry/utils": "7.66.0", + "tslib": "^2.4.1 || ^1.9.3" + }, "engines": { "node": ">=8" } }, - "node_modules/@sentry/utils": { - "version": "7.63.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.63.0.tgz", - "integrity": "sha512-7FQv1RYAwnuTuarruP+1+Jd6YQuN7i/Y7KltwPMVEwU7j5mzYQaexLr/Jz1XIdR2KYVdkbXQyP8jj8BmA6u9Jw==", + "node_modules/@sentry/node/node_modules/@sentry/types": { + "version": "7.66.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.66.0.tgz", + "integrity": "sha512-uUMSoSiar6JhuD8p7ON/Ddp4JYvrVd2RpwXJRPH1A4H4Bd4DVt1mKJy1OLG6HdeQv39XyhB1lPZckKJg4tATPw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/node/node_modules/@sentry/utils": { + "version": "7.66.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.66.0.tgz", + "integrity": "sha512-9GYUVgXjK66uXXcLXVMXVzlptqMtq1eJENCuDeezQiEFrNA71KkLDg00wESp+LL+bl3wpVTBApArpbF6UEG5hQ==", "dependencies": { - "@sentry/types": "7.63.0", + "@sentry/types": "7.66.0", "tslib": "^2.4.1 || ^1.9.3" }, "engines": { diff --git a/package.json b/package.json index 70e4ae84..3994670b 100644 --- a/package.json +++ b/package.json @@ -66,9 +66,8 @@ }, "dependencies": { "@aws-sdk/client-s3": "^3.385.0", - "@sentry/integrations": "^7.61.1", - "@sentry/node": "^7.61.1", - "@sentry/tracing": "^7.61.1", + "@sentry/integrations": "^7.66.0", + "@sentry/node": "^7.66.0", "ajv": "8.6.2", "ajv-formats": "2.1.1", "amqplib": "^0.10.3", diff --git a/src/util/util/Sentry.ts b/src/util/util/Sentry.ts index e302da0c..74a23a1e 100644 --- a/src/util/util/Sentry.ts +++ b/src/util/util/Sentry.ts @@ -16,13 +16,12 @@ along with this program. If not, see . */ -import { Config } from "./Config"; import { yellow } from "picocolors"; +import { Config } from "./Config"; -import express from "express"; -import * as SentryNode from "@sentry/node"; -import * as Tracing from "@sentry/tracing"; import * as Integrations from "@sentry/integrations"; +import * as SentryNode from "@sentry/node"; +import express from "express"; // Work around for when bundle calls api/etc let errorHandlersUsed = false; @@ -46,16 +45,28 @@ export const Sentry = { ); } + const integrations = [ + new SentryNode.Integrations.Http({ tracing: true }), + new Integrations.RewriteFrames({ + root: __dirname, + }), + new SentryNode.Integrations.Http({ + tracing: true, + breadcrumbs: true, + }), + ...SentryNode.autoDiscoverNodePerformanceMonitoringIntegrations(), + ]; + + if (app) + integrations.push( + new SentryNode.Integrations.Express({ + app, + }), + ); + SentryNode.init({ dsn: endpoint, - integrations: [ - new SentryNode.Integrations.Http({ tracing: true }), - new Tracing.Integrations.Express({ app }), - new Tracing.Integrations.Mysql(), - new Integrations.RewriteFrames({ - root: __dirname, - }), - ], + integrations, tracesSampleRate: traceSampleRate, // naming? environment, }); From 2fc3c5dbd4910a18d5a0e18065236067c25c8918 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Sat, 2 Sep 2023 20:18:38 +1000 Subject: [PATCH 10/20] sentry db instrumentation for gateway events --- src/gateway/events/Message.ts | 55 ++++++++++++++++------------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/src/gateway/events/Message.ts b/src/gateway/events/Message.ts index 45790146..52d9edd8 100644 --- a/src/gateway/events/Message.ts +++ b/src/gateway/events/Message.ts @@ -16,15 +16,15 @@ along with this program. If not, see . */ -import { WebSocket, Payload, CLOSECODES, OPCODES } from "@spacebar/gateway"; -import OPCodeHandlers from "../opcodes"; -import { check } from "../opcodes/instanceOf"; -import WS from "ws"; -import { PayloadSchema, ErlpackType } from "@spacebar/util"; import * as Sentry from "@sentry/node"; +import { CLOSECODES, OPCODES, Payload, WebSocket } from "@spacebar/gateway"; +import { ErlpackType, PayloadSchema } from "@spacebar/util"; +import fs from "fs/promises"; import BigIntJson from "json-bigint"; import path from "path"; -import fs from "fs/promises"; +import WS from "ws"; +import OPCodeHandlers from "../opcodes"; +import { check } from "../opcodes/instanceOf"; const bigIntJson = BigIntJson({ storeAsString: true }); let erlpack: ErlpackType | null = null; @@ -88,33 +88,28 @@ export async function Message(this: WebSocket, buffer: WS.Data) { return; } - const transaction = - data.op != 1 - ? Sentry.startTransaction({ - op: OPCODES[data.op], - name: `GATEWAY ${OPCODES[data.op]}`, - data: { - ...data.d, - token: data?.d?.token ? "[Redacted]" : undefined, - }, - }) - : undefined; - try { - const ret = await OPCodeHandler.call(this, data); - Sentry.withScope((scope) => { - scope.setSpan(transaction); - scope.setUser({ id: this.user_id }); - transaction?.finish(); - }); - return ret; + return await Sentry.startActiveSpan( + { + op: "websocket.server", + name: `GATEWAY ${OPCODES[data.op]}`, + data: { + ...data.d, + token: data?.d?.token ? "[Redacted]" : undefined, + }, + }, + async () => { + const ret = await OPCodeHandler.call(this, data); + Sentry.setUser({ id: this.user_id }); + return ret; + }, + ); } catch (error) { - Sentry.withScope((scope) => { - scope.setSpan(transaction); - if (this.user_id) scope.setUser({ id: this.user_id }); - Sentry.captureException(error); + Sentry.captureException(error, { + user: { + id: this.user_id, + }, }); - transaction?.finish(); console.error(`Error: Op ${data.op}`, error); // if (!this.CLOSED && this.CLOSING) return this.close(CLOSECODES.Unknown_error); From 09f5b4f0bbb4d88e97d75dc014f549f2571cc135 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Sat, 2 Sep 2023 21:05:27 +1000 Subject: [PATCH 11/20] Fix identify throwing on invalid token instead of closing with auth failed close code --- src/gateway/opcodes/Identify.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/gateway/opcodes/Identify.ts b/src/gateway/opcodes/Identify.ts index e097e44c..9a3128d9 100644 --- a/src/gateway/opcodes/Identify.ts +++ b/src/gateway/opcodes/Identify.ts @@ -60,6 +60,14 @@ import { check } from "./instanceOf"; // TODO: user sharding // TODO: check privileged intents, if defined in the config +const tryGetUserFromToken = async (...args: Parameters) => { + try { + return (await checkToken(...args)).user; + } catch (e) { + return null; + } +}; + export async function onIdentify(this: WebSocket, data: Payload) { if (this.user_id) { // we've already identified @@ -74,7 +82,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { this.capabilities = new Capabilities(identify.capabilities || 0); - const { user } = await checkToken(identify.token, { + const user = await tryGetUserFromToken(identify.token, { relations: ["relationships", "relationships.to", "settings"], select: [...PrivateUserProjection, "relationships"], }); From c64a11572911ec520bcde2477ff15d4c0d65c235 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Sat, 2 Sep 2023 23:47:40 +1000 Subject: [PATCH 12/20] xkcd embed handler and improved generic handler --- src/api/util/utility/EmbedHandlers.ts | 73 +++++++++++++++++++-------- 1 file changed, 53 insertions(+), 20 deletions(-) diff --git a/src/api/util/utility/EmbedHandlers.ts b/src/api/util/utility/EmbedHandlers.ts index 15e3f67f..e8f39407 100644 --- a/src/api/util/utility/EmbedHandlers.ts +++ b/src/api/util/utility/EmbedHandlers.ts @@ -17,11 +17,11 @@ */ import { Config, Embed, EmbedType } from "@spacebar/util"; -import fetch, { RequestInit } from "node-fetch"; import * as cheerio from "cheerio"; -import probe from "probe-image-size"; import crypto from "crypto"; +import fetch, { RequestInit } from "node-fetch"; import { yellow } from "picocolors"; +import probe from "probe-image-size"; export const DEFAULT_FETCH_OPTIONS: RequestInit = { redirect: "follow", @@ -85,6 +85,7 @@ export const getMetaDescriptions = (text: string) => { const $ = cheerio.load(text); return { + type: getMeta($, "og:type"), title: getMeta($, "og:title") || $("title").first().text(), provider_name: getMeta($, "og:site_name"), author: getMeta($, "article:author"), @@ -96,6 +97,8 @@ export const getMetaDescriptions = (text: string) => { height: parseInt(getMeta($, "og:image:height") || "0"), url: getMeta($, "og:url"), youtube_embed: getMeta($, "og:video:secure_url"), + + $, }; }; @@ -116,7 +119,7 @@ const genericImageHandler = async (url: URL): Promise => { method: "HEAD", }); - let width, height, image; + let width: number, height: number, image: string | undefined; if (type.headers.get("content-type")?.indexOf("image") !== -1) { const result = await probe(url.href); @@ -181,9 +184,16 @@ export const EmbedHandlers: { return null; } + let embedType = EmbedType.link; + if (metas.type == "article") embedType = EmbedType.article; + if (metas.type == "object") embedType = EmbedType.article; // github + if (metas.type == "rich") embedType = EmbedType.rich; + + if (metas.width < 400) embedType = EmbedType.link; + return { url: url.href, - type: EmbedType.link, + type: embedType, title: metas.title, thumbnail: { width: metas.width, @@ -210,9 +220,7 @@ export const EmbedHandlers: { // TODO: facebook // have to use their APIs or something because they don't send the metas in initial html - "twitter.com": (url: URL) => { - return EmbedHandlers["www.twitter.com"](url); - }, + "twitter.com": (url) => EmbedHandlers["www.twitter.com"](url), "www.twitter.com": async (url: URL) => { const token = Config.get().external.twitter; if (!token) return null; @@ -345,15 +353,15 @@ export const EmbedHandlers: { }; }, - "pixiv.net": (url: URL) => { - return EmbedHandlers["www.pixiv.net"](url); - }, + // TODO: docs: Pixiv won't work without Imagor + "pixiv.net": (url) => EmbedHandlers["www.pixiv.net"](url), "www.pixiv.net": async (url: URL) => { const response = await doFetch(url); if (!response) return null; const metas = getMetaDescriptions(await response.text()); - // TODO: doesn't show images. think it's a bug in the cdn + if (!metas.image) return null; + return { url: url.href, type: EmbedType.image, @@ -407,9 +415,7 @@ export const EmbedHandlers: { }; }, - "reddit.com": (url: URL) => { - return EmbedHandlers["www.reddit.com"](url); - }, + "reddit.com": (url) => EmbedHandlers["www.reddit.com"](url), "www.reddit.com": async (url: URL) => { const res = await EmbedHandlers["default"](url); return { @@ -420,12 +426,9 @@ export const EmbedHandlers: { }, }; }, - "youtu.be": (url: URL) => { - return EmbedHandlers["www.youtube.com"](url); - }, - "youtube.com": (url: URL) => { - return EmbedHandlers["www.youtube.com"](url); - }, + + "youtu.be": (url) => EmbedHandlers["www.youtube.com"](url), + "youtube.com": (url) => EmbedHandlers["www.youtube.com"](url), "www.youtube.com": async (url: URL): Promise => { const response = await doFetch(url); if (!response) return null; @@ -466,6 +469,36 @@ export const EmbedHandlers: { }; }, + "www.xkcd.com": (url) => EmbedHandlers["xkcd.com"](url), + "xkcd.com": async (url) => { + const response = await doFetch(url); + if (!response) return null; + + const metas = getMetaDescriptions(await response.text()); + const hoverText = metas.$("#comic img").attr("title"); + + if (!metas.image) return null; + + const { width, height } = await probe(metas.image); + + return { + url: url.href, + type: EmbedType.rich, + title: `xkcd: ${metas.title}`, + image: { + width, + height, + url: metas.image, + proxy_url: getProxyUrl(new URL(metas.image), width, height), + }, + footer: hoverText + ? { + text: hoverText, + } + : undefined, + }; + }, + // the url is an image from this instance self: async (url: URL): Promise => { const result = await probe(url.href); From fb7409947cf022c864fdbb07be6c2ba6cba296c1 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Sun, 3 Sep 2023 13:41:45 +1000 Subject: [PATCH 13/20] Fix bug in embed handler where getMeta would not return undefined --- src/api/util/utility/EmbedHandlers.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/api/util/utility/EmbedHandlers.ts b/src/api/util/utility/EmbedHandlers.ts index e8f39407..af01a32f 100644 --- a/src/api/util/utility/EmbedHandlers.ts +++ b/src/api/util/utility/EmbedHandlers.ts @@ -78,7 +78,8 @@ export const getProxyUrl = ( const getMeta = ($: cheerio.CheerioAPI, name: string): string | undefined => { let elem = $(`meta[property="${name}"]`); if (!elem.length) elem = $(`meta[name="${name}"]`); - return elem.attr("content") || elem.text(); + const ret = elem.attr("content") || elem.text(); + return ret.trim().length == 0 ? undefined : ret; }; export const getMetaDescriptions = (text: string) => { @@ -168,7 +169,8 @@ export const EmbedHandlers: { const response = await doFetch(url); if (!response) return null; - const metas = getMetaDescriptions(await response.text()); + const text = await response.text(); + const metas = getMetaDescriptions(text); // TODO: handle video @@ -189,7 +191,7 @@ export const EmbedHandlers: { if (metas.type == "object") embedType = EmbedType.article; // github if (metas.type == "rich") embedType = EmbedType.rich; - if (metas.width < 400) embedType = EmbedType.link; + if (metas.width && metas.width < 400) embedType = EmbedType.link; return { url: url.href, From e64c34adea6ad918511f26c8c22ff76500d51ba3 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Sun, 3 Sep 2023 14:17:11 +1000 Subject: [PATCH 14/20] Rewrite thumbnail/image generation for embeds --- src/api/util/utility/EmbedHandlers.ts | 148 +++++++++++--------------- 1 file changed, 65 insertions(+), 83 deletions(-) diff --git a/src/api/util/utility/EmbedHandlers.ts b/src/api/util/utility/EmbedHandlers.ts index af01a32f..b1e6b866 100644 --- a/src/api/util/utility/EmbedHandlers.ts +++ b/src/api/util/utility/EmbedHandlers.ts @@ -16,7 +16,7 @@ along with this program. If not, see . */ -import { Config, Embed, EmbedType } from "@spacebar/util"; +import { Config, Embed, EmbedImage, EmbedType } from "@spacebar/util"; import * as cheerio from "cheerio"; import crypto from "crypto"; import fetch, { RequestInit } from "node-fetch"; @@ -35,6 +35,20 @@ export const DEFAULT_FETCH_OPTIONS: RequestInit = { method: "GET", }; +const makeEmbedImage = ( + url: string | undefined, + width: number | undefined, + height: number | undefined, +): Required | undefined => { + if (!url || !width || !height) return undefined; + return { + url, + width, + height, + proxy_url: getProxyUrl(new URL(url), width, height), + }; +}; + let hasWarnedAboutImagor = false; export const getProxyUrl = ( @@ -82,6 +96,15 @@ const getMeta = ($: cheerio.CheerioAPI, name: string): string | undefined => { return ret.trim().length == 0 ? undefined : ret; }; +const tryParseInt = (str: string | undefined) => { + if (!str) return undefined; + try { + return parseInt(str); + } catch (e) { + return undefined; + } +}; + export const getMetaDescriptions = (text: string) => { const $ = cheerio.load(text); @@ -94,8 +117,8 @@ export const getMetaDescriptions = (text: string) => { image: getMeta($, "og:image") || getMeta($, "twitter:image"), image_fallback: $(`image`).attr("src"), video_fallback: $(`video`).attr("src"), - width: parseInt(getMeta($, "og:image:width") || "0"), - height: parseInt(getMeta($, "og:image:height") || "0"), + width: tryParseInt(getMeta($, "og:image:width")), + height: tryParseInt(getMeta($, "og:image:height")), url: getMeta($, "og:url"), youtube_embed: getMeta($, "og:video:secure_url"), @@ -120,13 +143,11 @@ const genericImageHandler = async (url: URL): Promise => { method: "HEAD", }); - let width: number, height: number, image: string | undefined; + let image; if (type.headers.get("content-type")?.indexOf("image") !== -1) { const result = await probe(url.href); - width = result.width; - height = result.height; - image = url.href; + image = makeEmbedImage(url.href, result.width, result.height); } else if (type.headers.get("content-type")?.indexOf("video") !== -1) { // TODO return null; @@ -135,22 +156,19 @@ const genericImageHandler = async (url: URL): Promise => { const response = await doFetch(url); if (!response) return null; const metas = getMetaDescriptions(await response.text()); - width = metas.width; - height = metas.height; - image = metas.image || metas.image_fallback; + image = makeEmbedImage( + metas.image || metas.image_fallback, + metas.width, + metas.height, + ); } - if (!width || !height || !image) return null; + if (!image) return null; return { url: url.href, type: EmbedType.image, - thumbnail: { - width: width, - height: height, - url: url.href, - proxy_url: getProxyUrl(new URL(image), width, height), - }, + thumbnail: image, }; }; @@ -176,13 +194,15 @@ export const EmbedHandlers: { if (!metas.image) metas.image = metas.image_fallback; + let image: Required | undefined; + if (metas.image && (!metas.width || !metas.height)) { const result = await probe(metas.image); - metas.width = result.width; - metas.height = result.height; + image = makeEmbedImage(metas.image, result.width, result.height); } - if (!metas.image && (!metas.title || !metas.description)) { + if (!image && (!metas.title || !metas.description)) { + // we don't have any content to display return null; } @@ -191,24 +211,11 @@ export const EmbedHandlers: { if (metas.type == "object") embedType = EmbedType.article; // github if (metas.type == "rich") embedType = EmbedType.rich; - if (metas.width && metas.width < 400) embedType = EmbedType.link; - return { url: url.href, type: embedType, title: metas.title, - thumbnail: { - width: metas.width, - height: metas.height, - url: metas.image, - proxy_url: metas.image - ? getProxyUrl( - new URL(metas.image), - metas.width, - metas.height, - ) - : undefined, - }, + thumbnail: image, description: metas.description, }; }, @@ -340,14 +347,7 @@ export const EmbedHandlers: { type: EmbedType.link, title: metas.title, description: metas.description, - thumbnail: { - width: 640, - height: 640, - proxy_url: metas.image - ? getProxyUrl(new URL(metas.image), 640, 640) - : undefined, - url: metas.image, - }, + thumbnail: makeEmbedImage(metas.image, 640, 640), provider: { url: "https://spotify.com", name: "Spotify", @@ -369,18 +369,11 @@ export const EmbedHandlers: { type: EmbedType.image, title: metas.title, description: metas.description, - image: { - width: metas.width, - height: metas.height, - url: url.href, - proxy_url: metas.image - ? getProxyUrl( - new URL(metas.image), - metas.width, - metas.height, - ) - : undefined, - }, + image: makeEmbedImage( + metas.image || metas.image_fallback, + metas.width, + metas.height, + ), provider: { url: "https://pixiv.net", name: "Pixiv", @@ -437,37 +430,31 @@ export const EmbedHandlers: { const metas = getMetaDescriptions(await response.text()); return { - video: { - // TODO: does this adjust with aspect ratio? - width: metas.width, - height: metas.height, - url: metas.youtube_embed, - }, + video: makeEmbedImage( + metas.youtube_embed, + metas.width, + metas.height, + ), url: url.href, - type: EmbedType.video, + type: metas.youtube_embed ? EmbedType.video : EmbedType.link, title: metas.title, - thumbnail: { - width: metas.width, - height: metas.height, - url: metas.image, - proxy_url: metas.image - ? getProxyUrl( - new URL(metas.image), - metas.width, - metas.height, - ) - : undefined, - }, + thumbnail: makeEmbedImage( + metas.image || metas.image_fallback, + metas.width, + metas.height, + ), provider: { url: "https://www.youtube.com", name: "YouTube", }, description: metas.description, color: 16711680, - author: { - name: metas.author, - // TODO: author channel url - }, + author: metas.author + ? { + name: metas.author, + // TODO: author channel url + } + : undefined, }; }, @@ -487,12 +474,7 @@ export const EmbedHandlers: { url: url.href, type: EmbedType.rich, title: `xkcd: ${metas.title}`, - image: { - width, - height, - url: metas.image, - proxy_url: getProxyUrl(new URL(metas.image), width, height), - }, + image: makeEmbedImage(metas.image, width, height), footer: hoverText ? { text: hoverText, From 1612832fc4f782a29988d2c9a1b928cfc00429e3 Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Sun, 3 Sep 2023 15:28:33 -0400 Subject: [PATCH 15/20] add facebook, and add steam fields --- assets/schemas.json | 922 +++++++++++--------------- src/api/util/utility/EmbedHandlers.ts | 57 +- 2 files changed, 451 insertions(+), 528 deletions(-) diff --git a/assets/schemas.json b/assets/schemas.json index 3891cee7..77df48bd 100644 --- a/assets/schemas.json +++ b/assets/schemas.json @@ -1410,7 +1410,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -3892,6 +3891,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -3928,9 +3930,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -5615,7 +5614,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -8097,6 +8095,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -8133,9 +8134,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -9820,7 +9818,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -12302,6 +12299,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -12338,9 +12338,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -14020,7 +14017,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -16502,6 +16498,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -16538,9 +16537,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -18256,7 +18252,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -20738,6 +20733,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -20774,9 +20772,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -22461,7 +22456,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -24943,6 +24937,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -24979,9 +24976,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -26657,7 +26651,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -29139,6 +29132,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -29175,9 +29171,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -30856,7 +30849,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -33338,6 +33330,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -33374,9 +33369,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -35064,7 +35056,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -37546,6 +37537,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -37582,9 +37576,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -39260,7 +39251,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -41742,6 +41732,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -41778,9 +41771,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -43456,7 +43446,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -45938,6 +45927,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -45974,9 +45966,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -47671,7 +47660,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -50153,6 +50141,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -50189,9 +50180,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -51870,7 +51858,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -54352,6 +54339,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -54388,9 +54378,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -56129,7 +56116,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -58611,6 +58597,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -58647,9 +58636,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -60347,7 +60333,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -62829,6 +62814,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -62865,9 +62853,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -64706,7 +64691,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -67188,6 +67172,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -67224,9 +67211,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -68923,7 +68907,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -71405,6 +71388,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -71441,9 +71427,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -73150,7 +73133,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -75632,6 +75614,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -75668,9 +75653,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -77359,7 +77341,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -79841,6 +79822,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -79877,9 +79861,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -81574,7 +81555,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -84056,6 +84036,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -84092,9 +84075,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -85779,7 +85759,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -88261,6 +88240,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -88297,9 +88279,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -89972,7 +89951,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -92454,6 +92432,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -92490,9 +92471,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -94276,7 +94254,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -96758,6 +96735,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -96794,9 +96774,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -98577,7 +98554,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -101059,6 +101035,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -101095,9 +101074,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -102773,7 +102749,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -105255,6 +105230,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -105291,9 +105269,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -106977,7 +106952,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -109459,6 +109433,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -109495,9 +109472,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -111174,7 +111148,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -113656,6 +113629,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -113692,9 +113668,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -115371,7 +115344,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -117853,6 +117825,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -117889,9 +117864,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -119603,7 +119575,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -122085,6 +122056,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -122121,9 +122095,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -123800,7 +123771,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -126282,6 +126252,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -126318,9 +126291,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -127996,7 +127966,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -130478,6 +130447,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -130514,9 +130486,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -132207,7 +132176,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -134689,6 +134657,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -134725,9 +134696,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -136407,7 +136375,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -138889,6 +138856,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -138925,9 +138895,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -140681,7 +140648,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -143163,6 +143129,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -143199,9 +143168,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -144877,7 +144843,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -147359,6 +147324,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -147395,9 +147363,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -149073,7 +149038,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -151555,6 +151519,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -151591,9 +151558,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -153266,7 +153230,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -155748,6 +155711,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -155784,9 +155750,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -157465,7 +157428,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -159947,6 +159909,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -159983,9 +159948,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -161674,7 +161636,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -164156,6 +164117,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -164192,9 +164156,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -165867,7 +165828,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -168349,6 +168309,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -168385,9 +168348,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -170109,7 +170069,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -172591,6 +172550,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -172627,9 +172589,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -174337,7 +174296,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -176819,6 +176777,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -176855,9 +176816,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -178530,7 +178488,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -181012,6 +180969,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -181048,9 +181008,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -182748,7 +182705,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -185230,6 +185186,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -185266,9 +185225,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -185891,6 +185847,16 @@ "UserSettingsSchema": { "type": "object", "properties": { + "status": { + "enum": [ + "dnd", + "idle", + "invisible", + "offline", + "online" + ], + "type": "string" + }, "afk_timeout": { "type": "integer" }, @@ -185988,16 +185954,6 @@ "show_current_game": { "type": "boolean" }, - "status": { - "enum": [ - "dnd", - "idle", - "invisible", - "offline", - "online" - ], - "type": "string" - }, "stream_notifications_enabled": { "type": "boolean" }, @@ -187055,7 +187011,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -189537,6 +189492,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -189573,9 +189531,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -191247,7 +191202,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -193729,6 +193683,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -193765,9 +193722,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -195478,7 +195432,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -197960,6 +197913,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -197996,9 +197952,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -199697,7 +199650,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -202179,6 +202131,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -202215,9 +202170,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -203968,7 +203920,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -206450,6 +206401,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -206486,9 +206440,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -208161,7 +208112,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -210643,6 +210593,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -210679,9 +210632,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -212362,7 +212312,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -214844,6 +214793,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -214880,9 +214832,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -216553,7 +216502,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -219035,6 +218983,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -219071,9 +219022,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -220750,7 +220698,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -223232,6 +223179,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -223268,9 +223218,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -224947,7 +224894,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -227429,6 +227375,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -227465,9 +227414,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -229144,7 +229090,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -231626,6 +231571,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -231662,9 +231610,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -233373,7 +233318,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -235855,6 +235799,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -235891,9 +235838,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -237574,7 +237518,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -240056,6 +239999,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -240092,9 +240038,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -241765,7 +241708,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -244247,6 +244189,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -244283,9 +244228,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -245962,7 +245904,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -248444,6 +248385,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -248480,9 +248424,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -250170,7 +250111,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -252652,6 +252592,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -252688,9 +252631,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -254392,7 +254332,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -256874,6 +256813,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -256910,9 +256852,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -258585,7 +258524,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -261067,6 +261005,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -261103,9 +261044,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -262781,7 +262719,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -265263,6 +265200,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -265299,9 +265239,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -267006,7 +266943,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -269488,6 +269424,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -269524,9 +269463,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -271199,7 +271135,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -273681,6 +273616,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -273717,9 +273655,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -275471,7 +275406,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -277953,6 +277887,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -277989,9 +277926,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -279671,7 +279605,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -282153,6 +282086,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -282189,9 +282125,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -283864,7 +283797,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -286346,6 +286278,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -286382,9 +286317,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -288057,7 +287989,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -290539,6 +290470,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -290575,9 +290509,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -292257,7 +292188,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -294739,6 +294669,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -294775,9 +294708,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -296454,7 +296384,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -298936,6 +298865,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -298972,9 +298904,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -300647,7 +300576,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -303129,6 +303057,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -303165,9 +303096,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -304915,7 +304843,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -307397,6 +307324,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -307433,9 +307363,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -309119,7 +309046,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -311601,6 +311527,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -311637,9 +311566,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -313324,7 +313250,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -315806,6 +315731,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -315842,9 +315770,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -317579,7 +317504,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -320061,6 +319985,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -320097,9 +320024,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -321793,7 +321717,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -324275,6 +324198,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -324311,9 +324237,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -326013,7 +325936,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -328495,6 +328417,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -328531,9 +328456,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -330227,7 +330149,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -332709,6 +332630,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -332745,9 +332669,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -334420,7 +334341,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -336902,6 +336822,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -336938,9 +336861,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -338641,7 +338561,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -341123,6 +341042,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -341159,9 +341081,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -342874,7 +342793,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -345356,6 +345274,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -345392,9 +345313,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -347061,7 +346979,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -349543,6 +349460,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -349579,9 +349499,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -351258,7 +351175,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -353740,6 +353656,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -353776,9 +353695,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -355451,7 +355367,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -357933,6 +357848,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -357969,9 +357887,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -359651,7 +359566,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -362133,6 +362047,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -362169,9 +362086,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -362843,6 +362757,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -362879,9 +362796,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -364048,7 +363962,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -366530,6 +366443,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -366566,9 +366482,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -368232,7 +368145,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -370714,6 +370626,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -370750,9 +370665,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -372510,7 +372422,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -374992,6 +374903,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -375028,9 +374942,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -376697,7 +376608,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -379179,6 +379089,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -379215,9 +379128,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -380884,7 +380794,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -383366,6 +383275,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -383402,9 +383314,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -385071,7 +384980,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -387553,6 +387461,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -387589,9 +387500,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -389352,7 +389260,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -391834,6 +391741,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -391870,9 +391780,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -393537,7 +393444,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -396019,6 +395925,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -396055,9 +395964,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -397722,7 +397628,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -400204,6 +400109,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -400240,9 +400148,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -401907,7 +401812,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -404389,6 +404293,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -404425,9 +404332,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -406094,7 +405998,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -408576,6 +408479,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -408612,9 +408518,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -410281,7 +410184,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -412763,6 +412665,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -412799,9 +412704,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -414468,7 +414370,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -416950,6 +416851,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -416986,9 +416890,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -418655,7 +418556,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -421137,6 +421037,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -421173,9 +421076,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -422842,7 +422742,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -425324,6 +425223,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -425360,9 +425262,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -427093,7 +426992,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -429575,6 +429473,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -429611,9 +429512,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -431280,7 +431178,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -433762,6 +433659,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -433798,9 +433698,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -435467,7 +435364,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -437949,6 +437845,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -437985,9 +437884,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -439654,7 +439550,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -442136,6 +442031,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -442172,9 +442070,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -443885,7 +443780,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -446367,6 +446261,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -446403,9 +446300,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -448301,7 +448195,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -450783,6 +450676,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -450819,9 +450715,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -452488,7 +452381,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -454970,6 +454862,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -455006,9 +454901,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -456675,7 +456567,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -459157,6 +459048,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -459193,9 +459087,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -460862,7 +460753,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -463344,6 +463234,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -463380,9 +463273,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -465049,7 +464939,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -467531,6 +467420,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -467567,9 +467459,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -469262,7 +469151,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -471744,6 +471632,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -471780,9 +471671,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -473449,7 +473337,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -475931,6 +475818,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -475967,9 +475857,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -477657,7 +477544,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -480139,6 +480025,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -480175,9 +480064,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -481858,7 +481744,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -484340,6 +484225,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -484376,9 +484264,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -486168,7 +486053,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -488650,6 +488534,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -488686,9 +488573,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -490373,7 +490257,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -492855,6 +492738,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -492891,9 +492777,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -494584,7 +494467,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -497066,6 +496948,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -497102,9 +496987,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -498781,7 +498663,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -501263,6 +501144,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -501299,9 +501183,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -502978,7 +502859,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -505460,6 +505340,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -505496,9 +505379,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -507162,7 +507042,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -509644,6 +509523,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -509680,9 +509562,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -511358,7 +511237,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -513840,6 +513718,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -513876,9 +513757,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -515569,7 +515447,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -518051,6 +517928,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -518087,9 +517967,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -519784,7 +519661,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -522266,6 +522142,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -522302,9 +522181,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -523978,7 +523854,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -526460,6 +526335,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -526496,9 +526374,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -528171,7 +528046,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -530653,6 +530527,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -530689,9 +530566,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -532364,7 +532238,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -534846,6 +534719,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -534882,9 +534758,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, @@ -536563,7 +536436,6 @@ "created_at", "default_thread_rate_limit_per_user", "flags", - "guild", "id", "nsfw", "owner", @@ -539045,6 +538917,9 @@ "banner": { "type": "string" }, + "description": { + "type": "string" + }, "unavailable": { "type": "boolean" }, @@ -539081,9 +538956,6 @@ "default_message_notifications": { "type": "integer" }, - "description": { - "type": "string" - }, "discovery_splash": { "type": "string" }, diff --git a/src/api/util/utility/EmbedHandlers.ts b/src/api/util/utility/EmbedHandlers.ts index b1e6b866..430ca4aa 100644 --- a/src/api/util/utility/EmbedHandlers.ts +++ b/src/api/util/utility/EmbedHandlers.ts @@ -226,8 +226,23 @@ export const EmbedHandlers: { "c.tenor.com": genericImageHandler, "media.tenor.com": genericImageHandler, - // TODO: facebook - // have to use their APIs or something because they don't send the metas in initial html + "facebook.com": (url) => EmbedHandlers["www.facebook.com"](url), + "www.facebook.com": async (url: URL) => { + const response = await doFetch(url); + if (!response) return null; + const metas = getMetaDescriptions(await response.text()); + + return { + url: url.href, + type: EmbedType.link, + title: metas.title, + description: metas.description, + thumbnail: makeEmbedImage(metas.image, 640, 640), + provider: { + name: "Facebook", + }, + }; + }, "twitter.com": (url) => EmbedHandlers["www.twitter.com"](url), "www.twitter.com": async (url: URL) => { @@ -385,6 +400,42 @@ export const EmbedHandlers: { const response = await doFetch(url); if (!response) return null; const metas = getMetaDescriptions(await response.text()); + const numReviews = metas.$("#review_summary_num_reviews").val() as + | string + | undefined; + const price = metas + .$(".game_purchase_price.price") + .data("price-final") as number | undefined; + const releaseDate = metas + .$(".release_date") + .find("div.date") + .text() + .trim(); + const isReleased = new Date(releaseDate) < new Date(); + + const fields: Embed["fields"] = []; + + if (numReviews) + fields.push({ + name: "Reviews", + value: numReviews, + inline: true, + }); + + if (price) + fields.push({ + name: "Price", + value: `$${price / 100}`, + inline: true, + }); + + // if the release date is in the past, it's already out + if (releaseDate && !isReleased) + fields.push({ + name: "Release Date", + value: releaseDate, + inline: true, + }); return { url: url.href, @@ -405,7 +456,7 @@ export const EmbedHandlers: { url: "https://store.steampowered.com", name: "Steam", }, - // TODO: fields for release date + fields, // TODO: Video }; }, From 8a35664ae630e960bf44f01497100e318231effb Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Sun, 3 Sep 2023 15:48:55 -0400 Subject: [PATCH 16/20] [fb] remove provider obj, add color --- src/api/util/utility/EmbedHandlers.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/api/util/utility/EmbedHandlers.ts b/src/api/util/utility/EmbedHandlers.ts index 430ca4aa..ab953613 100644 --- a/src/api/util/utility/EmbedHandlers.ts +++ b/src/api/util/utility/EmbedHandlers.ts @@ -238,9 +238,7 @@ export const EmbedHandlers: { title: metas.title, description: metas.description, thumbnail: makeEmbedImage(metas.image, 640, 640), - provider: { - name: "Facebook", - }, + color: 16777215, }; }, From add16ab26eb37cace5663980cb3c3042871b7693 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Tue, 5 Sep 2023 23:29:22 +1000 Subject: [PATCH 17/20] * allow limit=1 * fix GET messages?around order --- .../channels/#channel_id/messages/index.ts | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/api/routes/channels/#channel_id/messages/index.ts b/src/api/routes/channels/#channel_id/messages/index.ts index c384a05b..a5bfcfd7 100644 --- a/src/api/routes/channels/#channel_id/messages/index.ts +++ b/src/api/routes/channels/#channel_id/messages/index.ts @@ -40,7 +40,13 @@ import { import { Request, Response, Router } from "express"; import { HTTPError } from "lambert-server"; import multer from "multer"; -import { FindManyOptions, FindOperator, LessThan, MoreThan } from "typeorm"; +import { + FindManyOptions, + FindOperator, + LessThan, + MoreThan, + MoreThanOrEqual, +} from "typeorm"; import { URL } from "url"; const router: Router = Router(); @@ -122,12 +128,24 @@ router.get( if (around) { query.take = Math.floor(limit / 2); - const [right, left] = await Promise.all([ - Message.find({ ...query, where: { id: LessThan(around) } }), - Message.find({ ...query, where: { id: MoreThan(around) } }), - ]); - right.push(...left); - messages = right; + if (query.take != 0) { + const [right, left] = await Promise.all([ + Message.find({ ...query, where: { id: LessThan(around) } }), + Message.find({ + ...query, + where: { id: MoreThanOrEqual(around) }, + }), + ]); + left.push(...right); + messages = left; + } else { + query.take = 1; + const message = await Message.findOne({ + ...query, + where: { id: around }, + }); + messages = message ? [message] : []; + } } else { if (after) { if (BigInt(after) > BigInt(Snowflake.generate())) From d55f755d6c8018cb4608f7e4315a11ad5bafc6bf Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Wed, 13 Sep 2023 19:43:54 +1000 Subject: [PATCH 18/20] Add simple about and clients to readme #1098 --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c990c1d1..9e1d9490 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,9 @@ ## [About](https://spacebar.chat) +Spacebar/server is a Discord backend re-implementation and extension. +We aim to reverse engineer and add additional features to the Discord backend, while remaining completely backwards compatible with existing bots, applications, and clients. + This repository contains: - [Spacebar HTTP API Server](/src/api) @@ -23,6 +26,13 @@ This repository contains: - [HTTP CDN Server](/src/cdn) - [Utility and Database Models](/src/util) +## [Documentation](https://docs.spacebar.chat) + ## [Contributing](https://docs.spacebar.chat/contributing/) -## [Setup](https://docs.spacebar.chat/setup/server/) +## Clients + +You *should* be able to use any client designed for Discord.com to connect to a Spacebar instance. +However, some incompatibilities still exist between Spacebar and Discord. For this reason, not every client will connect. +The [WIP official Spacebar client](https://github.com/spacebarchat/client) will always work. +You can find a [live version here](https://app.spacebar.chat). From e355be8ea3f82552ca021a918efbaa86d3a1ba88 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Sat, 16 Sep 2023 23:43:23 +1000 Subject: [PATCH 19/20] Fix regression where generic embed handler wouldn't properly send image results --- src/api/util/utility/EmbedHandlers.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/api/util/utility/EmbedHandlers.ts b/src/api/util/utility/EmbedHandlers.ts index ab953613..f39db9c3 100644 --- a/src/api/util/utility/EmbedHandlers.ts +++ b/src/api/util/utility/EmbedHandlers.ts @@ -194,14 +194,13 @@ export const EmbedHandlers: { if (!metas.image) metas.image = metas.image_fallback; - let image: Required | undefined; - if (metas.image && (!metas.width || !metas.height)) { const result = await probe(metas.image); - image = makeEmbedImage(metas.image, result.width, result.height); + metas.width = result.width; + metas.height = result.height; } - if (!image && (!metas.title || !metas.description)) { + if (!metas.image && (!metas.title || !metas.description)) { // we don't have any content to display return null; } @@ -215,7 +214,7 @@ export const EmbedHandlers: { url: url.href, type: embedType, title: metas.title, - thumbnail: image, + thumbnail: makeEmbedImage(metas.image, metas.width, metas.height), description: metas.description, }; }, From c802bb9747bedcfd1ca4e2483e9fe53d6678d4fd Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Sat, 16 Sep 2023 23:47:32 +1000 Subject: [PATCH 20/20] Embeds: handle og:sitename --- src/api/util/utility/EmbedHandlers.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/api/util/utility/EmbedHandlers.ts b/src/api/util/utility/EmbedHandlers.ts index f39db9c3..0f1e88a5 100644 --- a/src/api/util/utility/EmbedHandlers.ts +++ b/src/api/util/utility/EmbedHandlers.ts @@ -121,6 +121,7 @@ export const getMetaDescriptions = (text: string) => { height: tryParseInt(getMeta($, "og:image:height")), url: getMeta($, "og:url"), youtube_embed: getMeta($, "og:video:secure_url"), + site_name: getMeta($, "og:site_name"), $, }; @@ -216,6 +217,12 @@ export const EmbedHandlers: { title: metas.title, thumbnail: makeEmbedImage(metas.image, metas.width, metas.height), description: metas.description, + provider: metas.site_name + ? { + name: metas.site_name, + url: url.origin, + } + : undefined, }; },