diff --git a/src/util/config/types/subconfigurations/limits/RateLimits.ts b/src/util/config/types/subconfigurations/limits/RateLimits.ts
index caba740b..0ce0827c 100644
--- a/src/util/config/types/subconfigurations/limits/RateLimits.ts
+++ b/src/util/config/types/subconfigurations/limits/RateLimits.ts
@@ -16,11 +16,11 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { RouteRateLimit, RateLimitOptions } from ".";
+import { RateLimitOptions, RouteRateLimit } from ".";
export class RateLimits {
enabled: boolean = false;
- ip: Omit<RateLimitOptions, "bot_count"> = {
+ ip: RateLimitOptions = {
count: 500,
window: 5,
};
diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts
index 9ce04848..e23d93db 100644
--- a/src/util/entities/Channel.ts
+++ b/src/util/entities/Channel.ts
@@ -482,3 +482,27 @@ export enum ChannelPermissionOverwriteType {
member = 1,
group = 2,
}
+
+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:
+ case ChannelType.DIRECTORY:
+ throw new HTTPError("not a text channel", 400);
+ case ChannelType.DM:
+ case ChannelType.GROUP_DM:
+ case ChannelType.GUILD_NEWS:
+ case ChannelType.GUILD_NEWS_THREAD:
+ case ChannelType.GUILD_PUBLIC_THREAD:
+ case ChannelType.GUILD_PRIVATE_THREAD:
+ case ChannelType.GUILD_TEXT:
+ case ChannelType.ENCRYPTED:
+ case ChannelType.ENCRYPTED_THREAD:
+ return true;
+ default:
+ throw new HTTPError("unimplemented", 400);
+ }
+}
diff --git a/src/util/entities/Guild.ts b/src/util/entities/Guild.ts
index e8454986..e2b3e1bd 100644
--- a/src/util/entities/Guild.ts
+++ b/src/util/entities/Guild.ts
@@ -24,7 +24,7 @@ import {
OneToMany,
RelationId,
} from "typeorm";
-import { Config, handleFile, Snowflake } from "..";
+import { Config, GuildWelcomeScreen, handleFile, Snowflake } from "..";
import { Ban } from "./Ban";
import { BaseClass } from "./BaseClass";
import { Channel } from "./Channel";
@@ -77,7 +77,7 @@ export class Guild extends BaseClass {
afk_channel?: Channel;
@Column({ nullable: true })
- afk_timeout?: number = Config.get().defaults.guild.afkTimeout;
+ afk_timeout?: number;
// * commented out -> use owner instead
// application id of the guild creator if it is bot-created
@@ -95,8 +95,7 @@ export class Guild extends BaseClass {
banner?: string;
@Column({ nullable: true })
- default_message_notifications?: number =
- Config.get().defaults.guild.defaultMessageNotifications;
+ default_message_notifications?: number;
@Column({ nullable: true })
description?: string;
@@ -105,11 +104,10 @@ export class Guild extends BaseClass {
discovery_splash?: string;
@Column({ nullable: true })
- explicit_content_filter?: number =
- Config.get().defaults.guild.explicitContentFilter;
+ explicit_content_filter?: number;
@Column({ type: "simple-array" })
- features: string[] = Config.get().guild.defaultFeatures || []; //TODO use enum
+ features: string[] = []; //TODO use enum
//TODO: https://discord.com/developers/docs/resources/guild#guild-object-guild-features
@Column({ nullable: true })
@@ -122,14 +120,13 @@ export class Guild extends BaseClass {
large?: boolean = false;
@Column({ nullable: true })
- max_members?: number = Config.get().limits.guild.maxMembers;
+ max_members?: number;
@Column({ nullable: true })
- max_presences?: number = Config.get().defaults.guild.maxPresences;
+ max_presences?: number;
@Column({ nullable: true })
- max_video_channel_users?: number =
- Config.get().defaults.guild.maxVideoChannelUsers;
+ max_video_channel_users?: number;
@Column({ nullable: true })
member_count?: number;
@@ -247,7 +244,7 @@ export class Guild extends BaseClass {
rules_channel?: string;
@Column({ nullable: true })
- region?: string = Config.get().regions.default;
+ region?: string;
@Column({ nullable: true })
splash?: string;
@@ -270,16 +267,7 @@ export class Guild extends BaseClass {
verification_level?: number;
@Column({ type: "simple-json" })
- welcome_screen: {
- enabled: boolean;
- description: string;
- welcome_channels: {
- description: string;
- emoji_id?: string;
- emoji_name?: string;
- channel_id: string;
- }[];
- };
+ welcome_screen: GuildWelcomeScreen;
@Column({ nullable: true })
@RelationId((guild: Guild) => guild.widget_channel)
@@ -336,6 +324,18 @@ export class Guild extends BaseClass {
description: "Fill in your description",
welcome_channels: [],
},
+
+ afk_timeout: Config.get().defaults.guild.afkTimeout,
+ default_message_notifications:
+ Config.get().defaults.guild.defaultMessageNotifications,
+ explicit_content_filter:
+ Config.get().defaults.guild.explicitContentFilter,
+ features: Config.get().guild.defaultFeatures,
+ max_members: Config.get().limits.guild.maxMembers,
+ max_presences: Config.get().defaults.guild.maxPresences,
+ max_video_channel_users:
+ Config.get().defaults.guild.maxVideoChannelUsers,
+ region: Config.get().regions.default,
}).save();
// we have to create the role _after_ the guild because else we would get a "SQLITE_CONSTRAINT: FOREIGN KEY constraint failed" error
diff --git a/src/util/entities/User.ts b/src/util/entities/User.ts
index df9af328..3e72c3c9 100644
--- a/src/util/entities/User.ts
+++ b/src/util/entities/User.ts
@@ -26,11 +26,11 @@ import {
OneToOne,
} from "typeorm";
import {
- adjustEmail,
Config,
Email,
FieldErrors,
Snowflake,
+ adjustEmail,
trimSpecial,
} from "..";
import { BitField } from "../util/BitField";
@@ -86,8 +86,7 @@ export const PrivateUserProjection = [
// Private user data that should never get sent to the client
export type PublicUser = Pick<User, PublicUserKeys>;
-
-export type UserPublic = Pick<User, PublicUserKeys>;
+export type PrivateUser = Pick<User, PrivateUserKeys>;
export interface UserPrivate extends Pick<User, PrivateUserKeys> {
locale: string;
@@ -110,8 +109,10 @@ export class User extends BaseClass {
@Column({ nullable: true })
banner?: string; // hash of the user banner
+ // TODO: Separate `User` and `UserProfile` models
+ // puyo: changed from [number, number] because it breaks openapi
@Column({ nullable: true, type: "simple-array" })
- theme_colors?: [number, number]; // TODO: Separate `User` and `UserProfile` models
+ theme_colors?: number[];
@Column({ nullable: true })
pronouns?: string;
@@ -126,10 +127,10 @@ export class User extends BaseClass {
mobile: boolean = false; // if the user has mobile app installed
@Column()
- premium: boolean = Config.get().defaults.user.premium ?? false; // if user bought individual premium
+ premium: boolean; // if user bought individual premium
@Column()
- premium_type: number = Config.get().defaults.user.premiumType ?? 0; // individual premium level
+ premium_type: number; // individual premium level
@Column()
bot: boolean = false; // if user is bot
@@ -156,13 +157,13 @@ export class User extends BaseClass {
totp_last_ticket?: string = "";
@Column()
- created_at: Date = new Date(); // registration date
+ created_at: Date; // registration date
@Column({ nullable: true })
premium_since: Date; // premium date
@Column({ select: false })
- verified: boolean = Config.get().defaults.user.verified ?? true; // email is verified
+ verified: boolean; // email is verified
@Column()
disabled: boolean = false; // if the account is disabled
@@ -381,11 +382,16 @@ export class User extends BaseClass {
valid_tokens_since: new Date(),
},
extended_settings: "{}",
+ settings: settings,
+
premium_since: Config.get().defaults.user.premium
? new Date()
: undefined,
- settings: settings,
rights: Config.get().register.defaultRights,
+ premium: Config.get().defaults.user.premium ?? false,
+ premium_type: Config.get().defaults.user.premiumType ?? 0,
+ verified: Config.get().defaults.user.verified ?? true,
+ created_at: new Date(),
});
user.validate();
diff --git a/src/util/interfaces/Activity.ts b/src/util/interfaces/Activity.ts
index 7654ba90..0227f242 100644
--- a/src/util/interfaces/Activity.ts
+++ b/src/util/interfaces/Activity.ts
@@ -36,7 +36,7 @@ export interface Activity {
};
party?: {
id?: string;
- size?: [number]; // used to show the party's current and maximum size // TODO: array length 2
+ size?: number[]; // used to show the party's current and maximum size // TODO: array length 2
};
assets?: {
large_image?: string; // the id for a large asset of the activity, usually a snowflake
diff --git a/src/util/interfaces/GuildWelcomeScreen.ts b/src/util/interfaces/GuildWelcomeScreen.ts
new file mode 100644
index 00000000..38b6061b
--- /dev/null
+++ b/src/util/interfaces/GuildWelcomeScreen.ts
@@ -0,0 +1,10 @@
+export interface GuildWelcomeScreen {
+ enabled: boolean;
+ description: string;
+ welcome_channels: {
+ description: string;
+ emoji_id?: string;
+ emoji_name?: string;
+ channel_id: string;
+ }[];
+}
diff --git a/src/util/interfaces/index.ts b/src/util/interfaces/index.ts
index c6a00458..6620ba32 100644
--- a/src/util/interfaces/index.ts
+++ b/src/util/interfaces/index.ts
@@ -19,6 +19,7 @@
export * from "./Activity";
export * from "./ConnectedAccount";
export * from "./Event";
+export * from "./GuildWelcomeScreen";
export * from "./Interaction";
export * from "./Presence";
export * from "./Status";
diff --git a/src/util/schemas/AckBulkSchema.ts b/src/util/schemas/AckBulkSchema.ts
index cf6dc597..5604c2fc 100644
--- a/src/util/schemas/AckBulkSchema.ts
+++ b/src/util/schemas/AckBulkSchema.ts
@@ -17,11 +17,9 @@
*/
export interface AckBulkSchema {
- read_states: [
- {
- channel_id: string;
- message_id: string;
- read_state_type: number; // WHat is this?
- },
- ];
+ read_states: {
+ channel_id: string;
+ message_id: string;
+ read_state_type: number; // WHat is this?
+ }[];
}
diff --git a/src/util/schemas/IdentifySchema.ts b/src/util/schemas/IdentifySchema.ts
index fb48c2a4..cb967aed 100644
--- a/src/util/schemas/IdentifySchema.ts
+++ b/src/util/schemas/IdentifySchema.ts
@@ -109,7 +109,11 @@ export interface IdentifySchema {
compress?: boolean;
large_threshold?: number;
largeThreshold?: number;
- shard?: [bigint, bigint];
+ /**
+ * @minItems 2
+ * @maxItems 2
+ */
+ shard?: bigint[]; // puyo: changed from [bigint, bigint] because it breaks openapi
guild_subscriptions?: boolean;
capabilities?: number;
client_state?: {
diff --git a/src/util/schemas/LazyRequestSchema.ts b/src/util/schemas/LazyRequestSchema.ts
index 63e67416..ee52d66c 100644
--- a/src/util/schemas/LazyRequestSchema.ts
+++ b/src/util/schemas/LazyRequestSchema.ts
@@ -18,7 +18,14 @@
export interface LazyRequestSchema {
guild_id: string;
- channels?: Record<string, [number, number][]>;
+ channels?: {
+ /**
+ * @items.type integer
+ * @minItems 2
+ * @maxItems 2
+ */
+ [key: string]: number[][]; // puyo: changed from [number, number] because it breaks openapi
+ };
activities?: boolean;
threads?: boolean;
typing?: true;
diff --git a/src/util/schemas/LoginResponse.ts b/src/util/schemas/LoginResponse.ts
new file mode 100644
index 00000000..faf3f769
--- /dev/null
+++ b/src/util/schemas/LoginResponse.ts
@@ -0,0 +1,14 @@
+import { TokenResponse } from "./responses";
+
+export interface MFAResponse {
+ ticket: string;
+ mfa: true;
+ sms: false; // TODO
+ token: null;
+}
+
+export interface WebAuthnResponse extends MFAResponse {
+ webauthn: string;
+}
+
+export type LoginResponse = TokenResponse | MFAResponse | WebAuthnResponse;
diff --git a/src/util/schemas/MemberChangeProfileSchema.ts b/src/util/schemas/MemberChangeProfileSchema.ts
index e955a0f1..d2d1481d 100644
--- a/src/util/schemas/MemberChangeProfileSchema.ts
+++ b/src/util/schemas/MemberChangeProfileSchema.ts
@@ -21,8 +21,7 @@ export interface MemberChangeProfileSchema {
nick?: string;
bio?: string;
pronouns?: string;
-
- /*
+ /**
* @items.type integer
*/
theme_colors?: [number, number];
diff --git a/src/util/schemas/UserGuildSettingsSchema.ts b/src/util/schemas/UserGuildSettingsSchema.ts
index c295f767..82edae9c 100644
--- a/src/util/schemas/UserGuildSettingsSchema.ts
+++ b/src/util/schemas/UserGuildSettingsSchema.ts
@@ -16,12 +16,12 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { UserGuildSettings, ChannelOverride } from "@spacebar/util";
+import { ChannelOverride, UserGuildSettings } from "@spacebar/util";
// This sucks. I would use a DeepPartial, my own or typeorms, but they both generate inncorect schema
export interface UserGuildSettingsSchema
extends Partial<Omit<UserGuildSettings, "channel_overrides">> {
channel_overrides?: {
- [channel_id: string]: Partial<ChannelOverride>;
+ [channel_id: string]: ChannelOverride;
};
}
diff --git a/src/util/schemas/UserNoteUpdateSchema.ts b/src/util/schemas/UserNoteUpdateSchema.ts
new file mode 100644
index 00000000..0a731279
--- /dev/null
+++ b/src/util/schemas/UserNoteUpdateSchema.ts
@@ -0,0 +1,3 @@
+export interface UserNoteUpdateSchema {
+ note: string;
+}
diff --git a/src/util/schemas/UserProfileModifySchema.ts b/src/util/schemas/UserProfileModifySchema.ts
index d49fe326..3dea257a 100644
--- a/src/util/schemas/UserProfileModifySchema.ts
+++ b/src/util/schemas/UserProfileModifySchema.ts
@@ -21,8 +21,7 @@ export interface UserProfileModifySchema {
accent_color?: number | null;
banner?: string | null;
pronouns?: string;
-
- /*
+ /**
* @items.type integer
*/
theme_colors?: [number, number];
diff --git a/src/util/schemas/UserProfileResponse.ts b/src/util/schemas/UserProfileResponse.ts
index 699d6a29..10bbcdbf 100644
--- a/src/util/schemas/UserProfileResponse.ts
+++ b/src/util/schemas/UserProfileResponse.ts
@@ -16,10 +16,10 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { PublicConnectedAccount, UserPublic } from "..";
+import { PublicConnectedAccount, PublicUser } from "..";
export interface UserProfileResponse {
- user: UserPublic;
+ user: PublicUser;
connected_accounts: PublicConnectedAccount;
premium_guild_since?: Date;
premium_since?: Date;
diff --git a/src/util/schemas/UserRelationsResponse.ts b/src/util/schemas/UserRelationsResponse.ts
deleted file mode 100644
index 38507420..00000000
--- a/src/util/schemas/UserRelationsResponse.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
- Copyright (C) 2023 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 <https://www.gnu.org/licenses/>.
-*/
-
-export interface UserRelationsResponse {
- object: {
- id?: string;
- username?: string;
- avatar?: string;
- discriminator?: string;
- public_flags?: number;
- };
-}
diff --git a/src/util/schemas/WebAuthnSchema.ts b/src/util/schemas/WebAuthnSchema.ts
index 652cda34..3f5e0da7 100644
--- a/src/util/schemas/WebAuthnSchema.ts
+++ b/src/util/schemas/WebAuthnSchema.ts
@@ -28,9 +28,9 @@ export interface CreateWebAuthnCredentialSchema {
ticket: string;
}
-export type WebAuthnPostSchema = Partial<
- GenerateWebAuthnCredentialsSchema | CreateWebAuthnCredentialSchema
->;
+export type WebAuthnPostSchema =
+ | GenerateWebAuthnCredentialsSchema
+ | CreateWebAuthnCredentialSchema;
export interface WebAuthnTotpSchema {
code: string;
diff --git a/src/util/schemas/index.ts b/src/util/schemas/index.ts
index 2d254752..44a504cd 100644
--- a/src/util/schemas/index.ts
+++ b/src/util/schemas/index.ts
@@ -69,6 +69,7 @@ export * from "./TotpSchema";
export * from "./UserDeleteSchema";
export * from "./UserGuildSettingsSchema";
export * from "./UserModifySchema";
+export * from "./UserNoteUpdateSchema";
export * from "./UserProfileModifySchema";
export * from "./UserSettingsSchema";
export * from "./Validator";
@@ -79,7 +80,4 @@ export * from "./VoiceVideoSchema";
export * from "./WebAuthnSchema";
export * from "./WebhookCreateSchema";
export * from "./WidgetModifySchema";
-export * from "./UserRelationsResponse";
-export * from "./GatewayResponse";
-export * from "./GatewayBotResponse";
-export * from "./UserProfileResponse";
+export * from "./responses";
diff --git a/src/util/schemas/responses/APIErrorOrCaptchaResponse.ts b/src/util/schemas/responses/APIErrorOrCaptchaResponse.ts
new file mode 100644
index 00000000..c9a0e5be
--- /dev/null
+++ b/src/util/schemas/responses/APIErrorOrCaptchaResponse.ts
@@ -0,0 +1,6 @@
+import { APIErrorResponse } from "./APIErrorResponse";
+import { CaptchaRequiredResponse } from "./CaptchaRequiredResponse";
+
+export type APIErrorOrCaptchaResponse =
+ | CaptchaRequiredResponse
+ | APIErrorResponse;
diff --git a/src/util/schemas/responses/APIErrorResponse.ts b/src/util/schemas/responses/APIErrorResponse.ts
new file mode 100644
index 00000000..25bb9504
--- /dev/null
+++ b/src/util/schemas/responses/APIErrorResponse.ts
@@ -0,0 +1,12 @@
+export interface APIErrorResponse {
+ code: number;
+ message: string;
+ errors: {
+ [key: string]: {
+ _errors: {
+ message: string;
+ code: string;
+ }[];
+ };
+ };
+}
diff --git a/src/util/schemas/responses/BackupCodesChallengeResponse.ts b/src/util/schemas/responses/BackupCodesChallengeResponse.ts
new file mode 100644
index 00000000..5473ad1f
--- /dev/null
+++ b/src/util/schemas/responses/BackupCodesChallengeResponse.ts
@@ -0,0 +1,4 @@
+export interface BackupCodesChallengeResponse {
+ nonce: string;
+ regenerate_nonce: string;
+}
diff --git a/src/util/schemas/responses/CaptchaRequiredResponse.ts b/src/util/schemas/responses/CaptchaRequiredResponse.ts
new file mode 100644
index 00000000..9f7f02ff
--- /dev/null
+++ b/src/util/schemas/responses/CaptchaRequiredResponse.ts
@@ -0,0 +1,5 @@
+export interface CaptchaRequiredResponse {
+ captcha_key: string;
+ captcha_sitekey: string;
+ captcha_service: string;
+}
diff --git a/src/util/schemas/responses/DiscoverableGuildsResponse.ts b/src/util/schemas/responses/DiscoverableGuildsResponse.ts
new file mode 100644
index 00000000..2a9fb1bd
--- /dev/null
+++ b/src/util/schemas/responses/DiscoverableGuildsResponse.ts
@@ -0,0 +1,8 @@
+import { Guild } from "../../entities";
+
+export interface DiscoverableGuildsResponse {
+ total: number;
+ guilds: Guild[];
+ offset: number;
+ limit: number;
+}
diff --git a/src/util/schemas/responses/GatewayBotResponse.ts b/src/util/schemas/responses/GatewayBotResponse.ts
new file mode 100644
index 00000000..30f1f57f
--- /dev/null
+++ b/src/util/schemas/responses/GatewayBotResponse.ts
@@ -0,0 +1,10 @@
+export interface GatewayBotResponse {
+ url: string;
+ shards: number;
+ session_start_limit: {
+ total: number;
+ remaining: number;
+ reset_after: number;
+ max_concurrency: number;
+ };
+}
diff --git a/src/util/schemas/responses/GatewayResponse.ts b/src/util/schemas/responses/GatewayResponse.ts
new file mode 100644
index 00000000..e909f7bd
--- /dev/null
+++ b/src/util/schemas/responses/GatewayResponse.ts
@@ -0,0 +1,3 @@
+export interface GatewayResponse {
+ url: string;
+}
diff --git a/src/util/schemas/responses/GenerateRegistrationTokensResponse.ts b/src/util/schemas/responses/GenerateRegistrationTokensResponse.ts
new file mode 100644
index 00000000..8816eabf
--- /dev/null
+++ b/src/util/schemas/responses/GenerateRegistrationTokensResponse.ts
@@ -0,0 +1,3 @@
+export interface GenerateRegistrationTokensResponse {
+ tokens: string[];
+}
diff --git a/src/util/schemas/responses/GuildBansResponse.ts b/src/util/schemas/responses/GuildBansResponse.ts
new file mode 100644
index 00000000..876a4bc4
--- /dev/null
+++ b/src/util/schemas/responses/GuildBansResponse.ts
@@ -0,0 +1,10 @@
+export interface GuildBansResponse {
+ reason: string;
+ user: {
+ username: string;
+ discriminator: string;
+ id: string;
+ avatar: string | null;
+ public_flags: number;
+ };
+}
diff --git a/src/util/schemas/responses/GuildCreateResponse.ts b/src/util/schemas/responses/GuildCreateResponse.ts
new file mode 100644
index 00000000..8185cb86
--- /dev/null
+++ b/src/util/schemas/responses/GuildCreateResponse.ts
@@ -0,0 +1,3 @@
+export interface GuildCreateResponse {
+ id: string;
+}
diff --git a/src/util/schemas/responses/GuildDiscoveryRequirements.ts b/src/util/schemas/responses/GuildDiscoveryRequirements.ts
new file mode 100644
index 00000000..731976f7
--- /dev/null
+++ b/src/util/schemas/responses/GuildDiscoveryRequirements.ts
@@ -0,0 +1,23 @@
+export interface GuildDiscoveryRequirementsResponse {
+ uild_id: string;
+ safe_environment: boolean;
+ healthy: boolean;
+ health_score_pending: boolean;
+ size: boolean;
+ nsfw_properties: unknown;
+ protected: boolean;
+ sufficient: boolean;
+ sufficient_without_grace_period: boolean;
+ valid_rules_channel: boolean;
+ retention_healthy: boolean;
+ engagement_healthy: boolean;
+ age: boolean;
+ minimum_age: number;
+ health_score: {
+ avg_nonnew_participators: number;
+ avg_nonnew_communicators: number;
+ num_intentful_joiners: number;
+ perc_ret_w1_intentful: number;
+ };
+ minimum_size: number;
+}
diff --git a/src/util/schemas/responses/GuildMessagesSearchResponse.ts b/src/util/schemas/responses/GuildMessagesSearchResponse.ts
new file mode 100644
index 00000000..0b6248b7
--- /dev/null
+++ b/src/util/schemas/responses/GuildMessagesSearchResponse.ts
@@ -0,0 +1,32 @@
+import {
+ Attachment,
+ Embed,
+ MessageType,
+ PublicUser,
+ Role,
+} from "../../entities";
+
+export interface GuildMessagesSearchMessage {
+ id: string;
+ type: MessageType;
+ content?: string;
+ channel_id: string;
+ author: PublicUser;
+ attachments: Attachment[];
+ embeds: Embed[];
+ mentions: PublicUser[];
+ mention_roles: Role[];
+ pinned: boolean;
+ mention_everyone?: boolean;
+ tts: boolean;
+ timestamp: string;
+ edited_timestamp: string | null;
+ flags: number;
+ components: unknown[];
+ hit: true;
+}
+
+export interface GuildMessagesSearchResponse {
+ messages: GuildMessagesSearchMessage[];
+ total_results: number;
+}
diff --git a/src/util/schemas/responses/GuildPruneResponse.ts b/src/util/schemas/responses/GuildPruneResponse.ts
new file mode 100644
index 00000000..fb1abb89
--- /dev/null
+++ b/src/util/schemas/responses/GuildPruneResponse.ts
@@ -0,0 +1,7 @@
+export interface GuildPruneResponse {
+ pruned: number;
+}
+
+export interface GuildPurgeResponse {
+ purged: number;
+}
diff --git a/src/util/schemas/responses/GuildRecommendationsResponse.ts b/src/util/schemas/responses/GuildRecommendationsResponse.ts
new file mode 100644
index 00000000..211670a6
--- /dev/null
+++ b/src/util/schemas/responses/GuildRecommendationsResponse.ts
@@ -0,0 +1,6 @@
+import { Guild } from "../../entities";
+
+export interface GuildRecommendationsResponse {
+ recommended_guilds: Guild[];
+ load_id: string;
+}
diff --git a/src/util/schemas/responses/GuildVanityUrl.ts b/src/util/schemas/responses/GuildVanityUrl.ts
new file mode 100644
index 00000000..ff37bf4e
--- /dev/null
+++ b/src/util/schemas/responses/GuildVanityUrl.ts
@@ -0,0 +1,17 @@
+export interface GuildVanityUrl {
+ code: string;
+ uses: number;
+}
+
+export interface GuildVanityUrlNoInvite {
+ code: null;
+}
+
+export type GuildVanityUrlResponse =
+ | GuildVanityUrl
+ | GuildVanityUrl[]
+ | GuildVanityUrlNoInvite;
+
+export interface GuildVanityUrlCreateResponse {
+ code: string;
+}
diff --git a/src/util/schemas/responses/GuildVoiceRegionsResponse.ts b/src/util/schemas/responses/GuildVoiceRegionsResponse.ts
new file mode 100644
index 00000000..8190d5fd
--- /dev/null
+++ b/src/util/schemas/responses/GuildVoiceRegionsResponse.ts
@@ -0,0 +1,7 @@
+export interface GuildVoiceRegion {
+ id: string;
+ name: string;
+ custom: boolean;
+ deprecated: boolean;
+ optimal: boolean;
+}
diff --git a/src/util/schemas/responses/GuildWidgetJsonResponse.ts b/src/util/schemas/responses/GuildWidgetJsonResponse.ts
new file mode 100644
index 00000000..ef85dd08
--- /dev/null
+++ b/src/util/schemas/responses/GuildWidgetJsonResponse.ts
@@ -0,0 +1,21 @@
+import { ClientStatus } from "../../interfaces";
+
+export interface GuildWidgetJsonResponse {
+ id: string;
+ name: string;
+ instant_invite: string;
+ channels: {
+ id: string;
+ name: string;
+ position: number;
+ }[];
+ members: {
+ id: string;
+ username: string;
+ discriminator: string;
+ avatar: string | null;
+ status: ClientStatus;
+ avatar_url: string;
+ }[];
+ presence_count: number;
+}
diff --git a/src/util/schemas/responses/GuildWidgetSettingsResponse.ts b/src/util/schemas/responses/GuildWidgetSettingsResponse.ts
new file mode 100644
index 00000000..3c6b45ce
--- /dev/null
+++ b/src/util/schemas/responses/GuildWidgetSettingsResponse.ts
@@ -0,0 +1,6 @@
+import { Snowflake } from "../../util";
+
+export interface GuildWidgetSettingsResponse {
+ enabled: boolean;
+ channel_id: Snowflake | null;
+}
diff --git a/src/util/schemas/responses/InstanceDomainsResponse.ts b/src/util/schemas/responses/InstanceDomainsResponse.ts
new file mode 100644
index 00000000..60367492
--- /dev/null
+++ b/src/util/schemas/responses/InstanceDomainsResponse.ts
@@ -0,0 +1,6 @@
+export interface InstanceDomainsResponse {
+ cdn: string;
+ gateway: string;
+ defaultApiVersion: string;
+ apiEndpoint: string;
+}
diff --git a/src/util/schemas/responses/InstancePingResponse.ts b/src/util/schemas/responses/InstancePingResponse.ts
new file mode 100644
index 00000000..5f1a9488
--- /dev/null
+++ b/src/util/schemas/responses/InstancePingResponse.ts
@@ -0,0 +1,13 @@
+export interface InstancePingResponse {
+ ping: "pong!";
+ instance: {
+ id: string;
+ name: string;
+ description: string | null;
+ image: string | null;
+ correspondenceEmail: string | null;
+ correspondenceUserID: string | null;
+ frontPage: string | null;
+ tosPage: string | null;
+ };
+}
diff --git a/src/util/schemas/responses/InstanceStatsResponse.ts b/src/util/schemas/responses/InstanceStatsResponse.ts
new file mode 100644
index 00000000..d24fd434
--- /dev/null
+++ b/src/util/schemas/responses/InstanceStatsResponse.ts
@@ -0,0 +1,8 @@
+export interface InstanceStatsResponse {
+ counts: {
+ user: number;
+ guild: number;
+ message: number;
+ members: number;
+ };
+}
diff --git a/src/util/schemas/responses/LocationMetadataResponse.ts b/src/util/schemas/responses/LocationMetadataResponse.ts
new file mode 100644
index 00000000..55337557
--- /dev/null
+++ b/src/util/schemas/responses/LocationMetadataResponse.ts
@@ -0,0 +1,5 @@
+export interface LocationMetadataResponse {
+ consent_required: boolean;
+ country_code: string;
+ promotional_email_opt_in: { required: true; pre_checked: false };
+}
diff --git a/src/util/schemas/responses/MemberJoinGuildResponse.ts b/src/util/schemas/responses/MemberJoinGuildResponse.ts
new file mode 100644
index 00000000..d7b39d10
--- /dev/null
+++ b/src/util/schemas/responses/MemberJoinGuildResponse.ts
@@ -0,0 +1,8 @@
+import { Emoji, Guild, Role, Sticker } from "../../entities";
+
+export interface MemberJoinGuildResponse {
+ guild: Guild;
+ emojis: Emoji[];
+ roles: Role[];
+ stickers: Sticker[];
+}
diff --git a/src/util/schemas/responses/OAuthAuthorizeResponse.ts b/src/util/schemas/responses/OAuthAuthorizeResponse.ts
new file mode 100644
index 00000000..60d6d2e2
--- /dev/null
+++ b/src/util/schemas/responses/OAuthAuthorizeResponse.ts
@@ -0,0 +1,3 @@
+export interface OAuthAuthorizeResponse {
+ location: string;
+}
diff --git a/src/util/schemas/responses/Tenor.ts b/src/util/schemas/responses/Tenor.ts
new file mode 100644
index 00000000..9dddf9d0
--- /dev/null
+++ b/src/util/schemas/responses/Tenor.ts
@@ -0,0 +1,72 @@
+export enum TenorMediaTypes {
+ gif,
+ mediumgif,
+ tinygif,
+ nanogif,
+ mp4,
+ loopedmp4,
+ tinymp4,
+ nanomp4,
+ webm,
+ tinywebm,
+ nanowebm,
+}
+
+export type TenorMedia = {
+ preview: string;
+ url: string;
+ dims: number[];
+ size: number;
+};
+
+export type TenorGif = {
+ created: number;
+ hasaudio: boolean;
+ id: string;
+ media: { [type in keyof typeof TenorMediaTypes]: TenorMedia }[];
+ tags: string[];
+ title: string;
+ itemurl: string;
+ hascaption: boolean;
+ url: string;
+};
+
+export type TenorCategory = {
+ searchterm: string;
+ path: string;
+ image: string;
+ name: string;
+};
+
+export type TenorCategoriesResults = {
+ tags: TenorCategory[];
+};
+
+export type TenorTrendingResults = {
+ next: string;
+ results: TenorGif[];
+ locale: string;
+};
+
+export type TenorSearchResults = {
+ next: string;
+ results: TenorGif[];
+};
+
+export interface TenorGifResponse {
+ id: string;
+ title: string;
+ url: string;
+ src: string;
+ gif_src: string;
+ width: number;
+ height: number;
+ preview: string;
+}
+
+export interface TenorTrendingResponse {
+ categories: TenorCategoriesResults;
+ gifs: TenorGifResponse[];
+}
+
+export type TenorGifsResponse = TenorGifResponse[];
diff --git a/src/util/schemas/responses/TokenResponse.ts b/src/util/schemas/responses/TokenResponse.ts
new file mode 100644
index 00000000..7e93055a
--- /dev/null
+++ b/src/util/schemas/responses/TokenResponse.ts
@@ -0,0 +1,15 @@
+import { BackupCode, UserSettings } from "../../entities";
+
+export interface TokenResponse {
+ token: string;
+ settings: UserSettings;
+}
+
+export interface TokenOnlyResponse {
+ token: string;
+}
+
+export interface TokenWithBackupCodesResponse {
+ token: string;
+ backup_codes: BackupCode[];
+}
diff --git a/src/util/schemas/responses/TypedResponses.ts b/src/util/schemas/responses/TypedResponses.ts
new file mode 100644
index 00000000..099efba3
--- /dev/null
+++ b/src/util/schemas/responses/TypedResponses.ts
@@ -0,0 +1,86 @@
+import { GeneralConfiguration, LimitsConfiguration } from "../../config";
+import { DmChannelDTO } from "../../dtos";
+import {
+ Application,
+ BackupCode,
+ Categories,
+ Channel,
+ Emoji,
+ Guild,
+ Invite,
+ Member,
+ Message,
+ PrivateUser,
+ PublicUser,
+ Role,
+ Sticker,
+ StickerPack,
+ Template,
+ Webhook,
+} from "../../entities";
+import { GuildVoiceRegion } from "./GuildVoiceRegionsResponse";
+
+// removes internal properties from the guild class
+export type APIGuild = Omit<
+ Guild,
+ | "afk_channel"
+ | "template"
+ | "owner"
+ | "public_updates_channel"
+ | "rules_channel"
+ | "system_channel"
+ | "widget_channel"
+>;
+
+export type APIPublicUser = PublicUser;
+export type APIPrivateUser = PrivateUser;
+
+export type APIGuildArray = APIGuild[];
+
+export type APIDMChannelArray = DmChannelDTO[];
+
+export type APIBackupCodeArray = BackupCode[];
+
+export interface UserUpdateResponse extends APIPrivateUser {
+ newToken?: string;
+}
+
+export type ApplicationDetectableResponse = unknown[];
+
+export type ApplicationEntitlementsResponse = unknown[];
+
+export type ApplicationSkusResponse = unknown[];
+
+export type APIApplicationArray = Application[];
+
+export type APIInviteArray = Invite[];
+
+export type APIMessageArray = Message[];
+
+export type APIWebhookArray = Webhook[];
+
+export type APIDiscoveryCategoryArray = Categories[];
+
+export type APIGeneralConfiguration = GeneralConfiguration;
+
+export type APIChannelArray = Channel[];
+
+export type APIEmojiArray = Emoji[];
+
+export type APIMemberArray = Member[];
+
+export interface APIGuildWithJoinedAt extends Guild {
+ joined_at: string;
+}
+
+export type APIRoleArray = Role[];
+
+export type APIStickerArray = Sticker[];
+
+export type APITemplateArray = Template[];
+
+export type APIGuildVoiceRegion = GuildVoiceRegion[];
+
+export type APILimitsConfiguration = LimitsConfiguration;
+
+export type APIStickerPackArray = StickerPack[];
diff --git a/src/util/schemas/responses/UpdatesResponse.ts b/src/util/schemas/responses/UpdatesResponse.ts
new file mode 100644
index 00000000..6b8566f4
--- /dev/null
+++ b/src/util/schemas/responses/UpdatesResponse.ts
@@ -0,0 +1,6 @@
+export interface UpdatesResponse {
+ name: string;
+ pub_date: string;
+ url: string;
+ notes: string | null;
+}
diff --git a/src/util/schemas/responses/UserNoteResponse.ts b/src/util/schemas/responses/UserNoteResponse.ts
new file mode 100644
index 00000000..b142811e
--- /dev/null
+++ b/src/util/schemas/responses/UserNoteResponse.ts
@@ -0,0 +1,5 @@
+export interface UserNoteResponse {
+ note: string;
+ note_user_id: string;
+ user_id: string;
+}
diff --git a/src/util/schemas/responses/UserProfileResponse.ts b/src/util/schemas/responses/UserProfileResponse.ts
new file mode 100644
index 00000000..bd1f46dd
--- /dev/null
+++ b/src/util/schemas/responses/UserProfileResponse.ts
@@ -0,0 +1,8 @@
+import { PublicConnectedAccount, PublicUser } from "../../entities";
+
+export interface UserProfileResponse {
+ user: PublicUser;
+ connected_accounts: PublicConnectedAccount;
+ premium_guild_since?: Date;
+ premium_since?: Date;
+}
diff --git a/src/util/schemas/responses/UserRelationsResponse.ts b/src/util/schemas/responses/UserRelationsResponse.ts
new file mode 100644
index 00000000..e784cafb
--- /dev/null
+++ b/src/util/schemas/responses/UserRelationsResponse.ts
@@ -0,0 +1,7 @@
+import { User } from "@spacebar/util";
+
+export type UserRelationsResponse = (Pick<User, "id"> &
+ Pick<User, "username"> &
+ Pick<User, "discriminator"> &
+ Pick<User, "avatar"> &
+ Pick<User, "public_flags">)[];
diff --git a/src/util/schemas/responses/UserRelationshipsResponse.ts b/src/util/schemas/responses/UserRelationshipsResponse.ts
new file mode 100644
index 00000000..dff2f118
--- /dev/null
+++ b/src/util/schemas/responses/UserRelationshipsResponse.ts
@@ -0,0 +1,8 @@
+import { PublicUser, RelationshipType } from "../../entities";
+
+export interface UserRelationshipsResponse {
+ id: string;
+ type: RelationshipType;
+ nickname: null;
+ user: PublicUser;
+}
diff --git a/src/util/schemas/responses/WebAuthnCreateResponse.ts b/src/util/schemas/responses/WebAuthnCreateResponse.ts
new file mode 100644
index 00000000..9aa9e206
--- /dev/null
+++ b/src/util/schemas/responses/WebAuthnCreateResponse.ts
@@ -0,0 +1,4 @@
+export interface WebAuthnCreateResponse {
+ name: string;
+ id: string;
+}
diff --git a/src/util/schemas/responses/WebhookCreateResponse.ts b/src/util/schemas/responses/WebhookCreateResponse.ts
new file mode 100644
index 00000000..ae142632
--- /dev/null
+++ b/src/util/schemas/responses/WebhookCreateResponse.ts
@@ -0,0 +1,6 @@
+import { User, Webhook } from "../../entities";
+
+export interface WebhookCreateResponse {
+ user: User;
+ hook: Webhook;
+}
diff --git a/src/util/schemas/responses/index.ts b/src/util/schemas/responses/index.ts
new file mode 100644
index 00000000..d8b7fd57
--- /dev/null
+++ b/src/util/schemas/responses/index.ts
@@ -0,0 +1,34 @@
+export * from "./APIErrorOrCaptchaResponse";
+export * from "./APIErrorResponse";
+export * from "./BackupCodesChallengeResponse";
+export * from "./CaptchaRequiredResponse";
+export * from "./DiscoverableGuildsResponse";
+export * from "./GatewayBotResponse";
+export * from "./GatewayResponse";
+export * from "./GenerateRegistrationTokensResponse";
+export * from "./GuildBansResponse";
+export * from "./GuildCreateResponse";
+export * from "./GuildDiscoveryRequirements";
+export * from "./GuildMessagesSearchResponse";
+export * from "./GuildPruneResponse";
+export * from "./GuildRecommendationsResponse";
+export * from "./GuildVanityUrl";
+export * from "./GuildVoiceRegionsResponse";
+export * from "./GuildWidgetJsonResponse";
+export * from "./GuildWidgetSettingsResponse";
+export * from "./InstanceDomainsResponse";
+export * from "./InstancePingResponse";
+export * from "./InstanceStatsResponse";
+export * from "./LocationMetadataResponse";
+export * from "./MemberJoinGuildResponse";
+export * from "./OAuthAuthorizeResponse";
+export * from "./Tenor";
+export * from "./TokenResponse";
+export * from "./TypedResponses";
+export * from "./UpdatesResponse";
+export * from "./UserNoteResponse";
+export * from "./UserProfileResponse";
+export * from "./UserRelationshipsResponse";
+export * from "./UserRelationsResponse";
+export * from "./WebAuthnCreateResponse";
+export * from "./WebhookCreateResponse";
diff --git a/src/util/util/Gifs.ts b/src/util/util/Gifs.ts
new file mode 100644
index 00000000..a5a5e64c
--- /dev/null
+++ b/src/util/util/Gifs.ts
@@ -0,0 +1,25 @@
+import { HTTPError } from "lambert-server";
+import { Config } from "./Config";
+import { TenorGif } from "..";
+
+export function parseGifResult(result: TenorGif) {
+ return {
+ id: result.id,
+ title: result.title,
+ url: result.itemurl,
+ src: result.media[0].mp4.url,
+ gif_src: result.media[0].gif.url,
+ width: result.media[0].mp4.dims[0],
+ height: result.media[0].mp4.dims[1],
+ preview: result.media[0].mp4.preview,
+ };
+}
+
+export function getGifApiKey() {
+ const { enabled, provider, apiKey } = Config.get().gif;
+ if (!enabled) throw new HTTPError(`Gifs are disabled`);
+ if (provider !== "tenor" || !apiKey)
+ throw new HTTPError(`${provider} gif provider not supported`);
+
+ return apiKey;
+}
diff --git a/src/util/util/index.ts b/src/util/util/index.ts
index 838239b7..3a98be15 100644
--- a/src/util/util/index.ts
+++ b/src/util/util/index.ts
@@ -41,3 +41,4 @@ export * from "./String";
export * from "./Token";
export * from "./TraverseDirectory";
export * from "./WebAuthn";
+export * from "./Gifs";
|