From 104e2aa0164387b4da2fa48e0947174d6e1c028a Mon Sep 17 00:00:00 2001 From: Rory& Date: Wed, 9 Sep 2026 21:00:07 +0200 Subject: [PATCH] Some schema fixes --- assets/openapi.json | Bin 1077943 -> 1073593 bytes assets/schemas.json | Bin 495901 -> 492697 bytes scripts/schemaExclusions.json | 1 - .../channels/#channel_id/messages/index.ts | 2 +- .../#channel_id/messages/pins/index.ts | 2 +- src/api/routes/channels/#channel_id/pins.ts | 2 +- .../routes/channels/#channel_id/webhooks.ts | 2 +- src/api/routes/channels/preload-messages.ts | 6 +- .../routes/guilds/#guild_id/members/index.ts | 2 +- src/api/routes/guilds/#guild_id/webhooks.ts | 2 +- src/api/routes/users/#user_id/index.ts | 2 +- src/api/routes/users/@me/index.ts | 2 +- src/schemas/api/channels/Webhook.ts | 2 +- src/schemas/api/guilds/Emoji.ts | 18 ++++ .../api/guilds/GuildScheduledEvents.ts | 24 +++++ src/schemas/api/guilds/GuildSchema.ts | 35 ++++++- src/schemas/api/guilds/Invite.ts | 88 ++++++++++++++++++ src/schemas/api/messages/Message.ts | 2 +- src/schemas/api/users/Member.ts | 2 +- src/schemas/responses/TypedResponses.ts | 6 +- 20 files changed, 180 insertions(+), 20 deletions(-) create mode 100644 src/schemas/api/guilds/GuildScheduledEvents.ts create mode 100644 src/schemas/api/guilds/Invite.ts diff --git a/assets/openapi.json b/assets/openapi.json index 62f4cbaa7f5acf0c5c28017dfcc925c1a38e67b6..cced6947ff7fb74aed5a6420a9eb3435b2bc4694 100644 GIT binary patch delta 635 zcmZ{gPe>GT6vz3^?9OjycV-;d(&%8DSeJq}O|U=6de}@1lq6gzWJOJc&~XzbFXf>I zL~~Q<3$Zbq5l9j(%Jwph3@_C|0%MUnv>mLA#!82TrD#Mp>d@g`zTeM#-^Z8MYUh_~ zlj|A0+2AS)%3Rlw8BtY4W>g=H-J(7*Va%;(dcIpzn~bJ5g@!23%>0GQ2)^Pad6d@M z#p#ns-V^!Gv7jPzB#M>2d1A*a>|`CZ_@4b@h}B8^kqCK9;jqWyZ{Sr3O71Y;T^0r= z7kwr0FNusKA=~Ht zIo8Whch+@TRQcDoZ8krv~r7o^3v*6p4&yUcX>%OuHP28mD=Kz z+LCKlc~i7|psl|Xg%vymb67c#$P4uxC7TtCk-4H|hLOF=%i(`4C@?Rm^HiGF#~6|| z9>YqvcqrZC?Ffr!yRV?I&#);`q{DY~K7Z?=yQqX;MyRa_ICzE+&b|4_G+2U&v;*VVYj>oRMQ&8GA7& zw_|{3Kv8B{Vo54O(R7DB91fEcI$|eJNK)ABzcPC+dit4p931V%eat}20>rG_i~HDY zZcS@rXWd>=&;Cth`uYrZw(YZu*>7@h&zr(79=shW@RV!%21a)F>G`kNIi`CAv&2kx z;ANlwAqr^K27YGt={ma19PM^5*tgrg;OM!|4D`eHQ~NoiT0pGn6ISz8Z*MT<;$UiD z?#8u!xf^#%#Pok_c^_`SaGhr%NK=Hl>Ne$TI-=km&Re&ouHK3KKw==#diWNafEOF%!C z7olZjj=C@6z)gXKP$^L*Kk;z>oXlPmk-e5O0Zbfl>p%G|LKd*+P)mUrjw8_wCb!Zx|$I}$=QN}m7V(~--zE7$1 z7b~c&vl{HeG=25WFwZHtP16qCQF4OQ6J|Hs+U@3m0>==sK@0L;xKqRlJ;1_An<|^3 oW|*+4e63%c75GJscv`^n*|RoxUhXfFxvr69>)OBfTGN@#FEs|;^_;^S=}ZV%yFOo;0mk6 z_5uZ_V~mp@1ba+R*v?Wm{lgq4%gG8H{M-LeXRP6BUq6X)`}#>tbL_WEUuL>yJUusp zouhq{05cG?05R+KNdj!iR@(z&*&+oYc5Ppo$HweAJ)w?`WBXq(w#gjRAM9dfpKh}Y L$ltx4?cNyxFd#uN diff --git a/scripts/schemaExclusions.json b/scripts/schemaExclusions.json index 82e545ab0..3305a4e4b 100644 --- a/scripts/schemaExclusions.json +++ b/scripts/schemaExclusions.json @@ -31,7 +31,6 @@ "UpdateRouteResponse", "MessagesSendAPIResponse", "APIWebhook", - "WebhookResponse", "WebhookValidationResponse", "MessageResponse", "ConnectionSettingsResponse", diff --git a/src/api/routes/channels/#channel_id/messages/index.ts b/src/api/routes/channels/#channel_id/messages/index.ts index c9b7a5406..762eae171 100644 --- a/src/api/routes/channels/#channel_id/messages/index.ts +++ b/src/api/routes/channels/#channel_id/messages/index.ts @@ -78,7 +78,7 @@ router.get( }, responses: { 200: { - body: "PublicMessageArray", + body: "PublicMessageListResponse", }, 400: { body: "APIErrorResponse", diff --git a/src/api/routes/channels/#channel_id/messages/pins/index.ts b/src/api/routes/channels/#channel_id/messages/pins/index.ts index 062084e58..1b1254b92 100644 --- a/src/api/routes/channels/#channel_id/messages/pins/index.ts +++ b/src/api/routes/channels/#channel_id/messages/pins/index.ts @@ -165,7 +165,7 @@ router.get( permission: ["READ_MESSAGE_HISTORY"], responses: { 200: { - body: "PublicMessageArray", + body: "PublicMessageListResponse", }, 400: { body: "APIErrorResponse", diff --git a/src/api/routes/channels/#channel_id/pins.ts b/src/api/routes/channels/#channel_id/pins.ts index 499e3a980..2169d05cc 100644 --- a/src/api/routes/channels/#channel_id/pins.ts +++ b/src/api/routes/channels/#channel_id/pins.ts @@ -166,7 +166,7 @@ router.get( permission: ["READ_MESSAGE_HISTORY"], responses: { 200: { - body: "PublicMessageArray", + body: "PublicMessageListResponse", }, 400: { body: "APIErrorResponse", diff --git a/src/api/routes/channels/#channel_id/webhooks.ts b/src/api/routes/channels/#channel_id/webhooks.ts index d38e18d7c..a27e1cf28 100644 --- a/src/api/routes/channels/#channel_id/webhooks.ts +++ b/src/api/routes/channels/#channel_id/webhooks.ts @@ -34,7 +34,7 @@ router.get( permission: "MANAGE_WEBHOOKS", responses: { 200: { - body: "WebhookArray", + body: "WebhookListResponse", }, }, }), diff --git a/src/api/routes/channels/preload-messages.ts b/src/api/routes/channels/preload-messages.ts index 8b860bc98..f8b0d9a09 100644 --- a/src/api/routes/channels/preload-messages.ts +++ b/src/api/routes/channels/preload-messages.ts @@ -20,7 +20,7 @@ import { Request, Response, Router } from "express"; import { route } from "@spacebar/api/middlewares"; import { Message } from "@spacebar/database"; import { Config } from "@spacebar/util"; -import { PreloadMessagesRequestSchema, PublicMessageArray } from "@spacebar/schemas"; +import { PreloadMessagesRequestSchema, PublicMessageListResponse } from "@spacebar/schemas"; const router = Router({ mergeParams: true }); @@ -30,7 +30,7 @@ router.post( requestBody: "PreloadMessagesRequestSchema", responses: { 200: { - body: "PublicMessageArray", + body: "PublicMessageListResponse", }, 400: { body: "APIErrorResponse", @@ -62,7 +62,7 @@ router.post( // https://docs.discord.food/resources/message#preload-messages - reactions are not included in the response x.reactions = undefined; return x; - }) as unknown as PublicMessageArray; + }) as unknown as PublicMessageListResponse; return res.status(200).send(filteredMessages); }, diff --git a/src/api/routes/guilds/#guild_id/members/index.ts b/src/api/routes/guilds/#guild_id/members/index.ts index ba8f4b3b9..fabc48f96 100644 --- a/src/api/routes/guilds/#guild_id/members/index.ts +++ b/src/api/routes/guilds/#guild_id/members/index.ts @@ -42,7 +42,7 @@ router.get( }, responses: { 200: { - body: "PublicMemberArray", + body: "PublicMemberListResponse", }, 403: { body: "APIErrorResponse", diff --git a/src/api/routes/guilds/#guild_id/webhooks.ts b/src/api/routes/guilds/#guild_id/webhooks.ts index 3ae2ad7ee..bc9c91a53 100644 --- a/src/api/routes/guilds/#guild_id/webhooks.ts +++ b/src/api/routes/guilds/#guild_id/webhooks.ts @@ -31,7 +31,7 @@ router.get( permission: "MANAGE_WEBHOOKS", responses: { 200: { - body: "WebhookArray", + body: "WebhookListResponse", }, }, }), diff --git a/src/api/routes/users/#user_id/index.ts b/src/api/routes/users/#user_id/index.ts index 228c87bb2..bee48dcb9 100644 --- a/src/api/routes/users/#user_id/index.ts +++ b/src/api/routes/users/#user_id/index.ts @@ -27,7 +27,7 @@ router.get( route({ responses: { 200: { - body: "APIPublicUser", + body: "PublicUser", }, }, }), diff --git a/src/api/routes/users/@me/index.ts b/src/api/routes/users/@me/index.ts index 2ed525e82..f58f87ff2 100644 --- a/src/api/routes/users/@me/index.ts +++ b/src/api/routes/users/@me/index.ts @@ -30,7 +30,7 @@ router.get( route({ responses: { 200: { - body: "APIPrivateUser", + body: "PrivateUser", }, }, }), diff --git a/src/schemas/api/channels/Webhook.ts b/src/schemas/api/channels/Webhook.ts index 22f78946f..fcceb1a83 100644 --- a/src/schemas/api/channels/Webhook.ts +++ b/src/schemas/api/channels/Webhook.ts @@ -29,7 +29,7 @@ export interface WebhookCreateResponse { hook: WebhookResponse; } -export type WebhookArray = WebhookResponse[]; +export type WebhookListResponse = WebhookResponse[]; export interface WebhookResponse { id: Snowflake; type: WebhookType; diff --git a/src/schemas/api/guilds/Emoji.ts b/src/schemas/api/guilds/Emoji.ts index b0b358fda..607434748 100644 --- a/src/schemas/api/guilds/Emoji.ts +++ b/src/schemas/api/guilds/Emoji.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2026 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { Snowflake } from "../../Identifiers"; import { PartialUser } from "../users"; diff --git a/src/schemas/api/guilds/GuildScheduledEvents.ts b/src/schemas/api/guilds/GuildScheduledEvents.ts new file mode 100644 index 000000000..11522da3f --- /dev/null +++ b/src/schemas/api/guilds/GuildScheduledEvents.ts @@ -0,0 +1,24 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2026 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +import { Snowflake } from "../../Identifiers"; + +export enum EventPrivacyLevel { + PUBLIC = 1, + GUILD_ONLY = 2, +} diff --git a/src/schemas/api/guilds/GuildSchema.ts b/src/schemas/api/guilds/GuildSchema.ts index a4c671c8a..96bb97391 100644 --- a/src/schemas/api/guilds/GuildSchema.ts +++ b/src/schemas/api/guilds/GuildSchema.ts @@ -1,6 +1,6 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. - Copyright (C) 2025 Spacebar and Spacebar Contributors + Copyright (C) 2026 Spacebar and Spacebar Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -28,3 +28,36 @@ export interface IntegrationGuild { name: string; icon: string | null; } + +export enum GuildVerificationLevel { + NONE = 0, + // Verified email + LOW = 1, + // Registered >5min ago + MEDIUM = 2, + // Member for >10min + HIGH = 3, + // Verified phone number + VERY_HIGH = 4, +} + +export enum GuildNsfwLevel { + DEFAULT = 0, + EXPLICIT = 1, + SAFE = 2, + AGE_RESTRICTED = 3, +} + +// Unlocked boost perk level +export enum GuildPremiumTier { + NONE = 0, + TIER_1 = 1, + TIER_2 = 2, + TIER_3 = 3, +} + +export enum GuildHubType { + DEFAULT = 0, + HIGH_SCHOOL = 1, + COLLEGE = 2, +} diff --git a/src/schemas/api/guilds/Invite.ts b/src/schemas/api/guilds/Invite.ts new file mode 100644 index 000000000..35e458592 --- /dev/null +++ b/src/schemas/api/guilds/Invite.ts @@ -0,0 +1,88 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2026 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +import { Snowflake } from "../../Identifiers"; +import { PartialUser } from "../users"; +import { GuildNsfwLevel, GuildPremiumTier, GuildVerificationLevel } from "./GuildSchema"; +import { GuildProfileResponse, PublicChannel, RoleColors } from "@spacebar/schemas"; +import { Role } from "@spacebar/database"; + +export interface Invite { + code: string; + type: number; + channel: PublicChannel | null; // TODO: Figure out what fields this is *supposed* to have as it's labeled as "Partial channel object" + guild_id?: Snowflake; + guild?: InviteGuild; + profile?: GuildProfileResponse; + inviter?: PartialUser; + flags?: number; + target_type?: number; + target_user?: PartialUser; + // target_application?: PartialApplication; // TODO - voice activities + roles?: InviteRole[]; // TODO: This is labeled as "Partial role object", is this used anywhere else? + approximate_member_count?: number; + approximate_presence_count?: number; + expires_at: string | null; + // guild_scheduled_event?: GuildScheduledEvent; //TODO - scheduled events + new_member?: boolean; + show_verification_form?: boolean; + is_nickname_changeable?: boolean; + target_users_job_status?: InviteTargetUsersJob; // TODO +} + +export interface InviteTargetUsersJob { + status: InviteTargetUsersJobStatus; + total_users: number; + processed_users: number; + created_at: Date | null; + completed_at: Date | null; + error_message: string | null; +} + +export enum InviteTargetUsersJobStatus { + UNSPECIFIED = 0, + PROCESSING = 1, + COMPLETED = 2, + FAILED = 3, +} + +export interface InviteGuild { + id: Snowflake; + name: string; + icon: string | null; + description: string | null; + banner: string | null; + splash: string | null; + verification_level: GuildVerificationLevel; + features: string[]; + vanity_url_code: string | null; + premium_subscription_count?: number; + premium_tier: GuildPremiumTier; + nsfw: boolean; + nsfw_level: GuildNsfwLevel; +} + +export interface InviteRole { + id: Snowflake; + name: string; + position: number; + color: number; + colors: RoleColors; + icon?: string | null; + unicode_emoji?: string | null; +} diff --git a/src/schemas/api/messages/Message.ts b/src/schemas/api/messages/Message.ts index 8d736aa68..b340a8637 100644 --- a/src/schemas/api/messages/Message.ts +++ b/src/schemas/api/messages/Message.ts @@ -163,7 +163,7 @@ export interface MessageSnapshot { }; } -export type PublicMessageArray = PublicMessage[]; +export type PublicMessageListResponse = PublicMessage[]; export interface PublicMessage { id: Snowflake; channel_id: Snowflake; diff --git a/src/schemas/api/users/Member.ts b/src/schemas/api/users/Member.ts index f6778509e..691b085bc 100644 --- a/src/schemas/api/users/Member.ts +++ b/src/schemas/api/users/Member.ts @@ -116,4 +116,4 @@ export type PublicMember = Omit, "roles"> & { roles: string[]; // only role ids not objects }; -export type PublicMemberArray = PublicMember[]; +export type PublicMemberListResponse = PublicMember[]; diff --git a/src/schemas/responses/TypedResponses.ts b/src/schemas/responses/TypedResponses.ts index e43114201..b37c4b741 100644 --- a/src/schemas/responses/TypedResponses.ts +++ b/src/schemas/responses/TypedResponses.ts @@ -21,17 +21,15 @@ import { GeneralConfiguration, LimitsConfiguration } from "../../util/config/typ import { DmChannelDTO } from "../../util/dtos"; // TODO: remove entity imports import { Application, Categories, Channel, Guild, Invite, Template } from "@spacebar/database"; -import { GuildCreateResponse, PrivateUser, PublicUser } from "@spacebar/schemas"; +import { GuildCreateResponse, PrivateUser } from "@spacebar/schemas"; // TODO: remove this entire file! // removes internal properties from the guild class export type APIGuild = Omit; -export type APIPublicUser = PublicUser; -export type APIPrivateUser = PrivateUser; export type APIGuildArray = APIGuild[]; export type APIDMChannelArray = DmChannelDTO[]; -export interface UserUpdateResponse extends APIPrivateUser { +export interface UserUpdateResponse extends PrivateUser { newToken?: string; }