diff --git a/assets/schemas.json b/assets/schemas.json
index 4efe4d5c..84fc55ad 100755
Binary files a/assets/schemas.json and b/assets/schemas.json differ
diff --git a/package-lock.json b/package-lock.json
index af6d8af7..573811e6 100644
Binary files a/package-lock.json and b/package-lock.json differ
diff --git a/package.json b/package.json
index f862ba8a..0609112f 100644
--- a/package.json
+++ b/package.json
@@ -62,6 +62,7 @@
"@types/ws": "^8.18.1",
"@typescript-eslint/eslint-plugin": "^8.35.1",
"@typescript-eslint/parser": "^8.35.1",
+ "discord-protos": "^1.2.43",
"eslint": "^9.30.1",
"express": "^4.21.2",
"globals": "^15.15.0",
diff --git a/scripts/schema.js b/scripts/schema.js
index fd5b09f5..b39948e7 100644
--- a/scripts/schema.js
+++ b/scripts/schema.js
@@ -112,7 +112,29 @@ function main() {
definitions = { ...definitions, [name]: { ...part } };
}
+ deleteOneOfKindUndefinedRecursive(definitions, "$");
+
fs.writeFileSync(schemaPath, JSON.stringify(definitions, null, 4));
}
+function deleteOneOfKindUndefinedRecursive(obj, path) {
+ if (
+ obj?.type === "object" &&
+ obj?.properties?.oneofKind?.type === "undefined"
+ )
+ return true;
+
+ for (const key in obj) {
+ if (
+ typeof obj[key] === "object" &&
+ deleteOneOfKindUndefinedRecursive(obj[key], path + "." + key)
+ ) {
+ console.log("Deleting", path, key);
+ delete obj[key];
+ }
+ }
+
+ return false;
+}
+
main();
diff --git a/src/api/routes/users/@me/settings-proto/1.ts b/src/api/routes/users/@me/settings-proto/1.ts
new file mode 100644
index 00000000..3ac64292
--- /dev/null
+++ b/src/api/routes/users/@me/settings-proto/1.ts
@@ -0,0 +1,187 @@
+/*
+ Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
+ Copyright (C) 2025 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 { route } from "@spacebar/api";
+import { Request, Response, Router } from "express";
+import {
+ OrmUtils,
+ SettingsProtoJsonResponse,
+ SettingsProtoResponse,
+ SettingsProtoUpdateJsonSchema,
+ SettingsProtoUpdateSchema,
+ UserSettingsProtos,
+} from "@spacebar/util";
+import { PreloadedUserSettings } from "discord-protos";
+
+const router: Router = Router();
+
+//#region Protobuf
+router.get(
+ "/",
+ route({
+ responses: {
+ 200: {
+ body: "SettingsProtoResponse",
+ },
+ },
+ query: {
+ atomic: {
+ type: "boolean",
+ description:
+ "Whether to try to apply the settings update atomically (default false)",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const userSettings = await UserSettingsProtos.getOrCreate(req.user_id);
+
+ res.json({
+ settings: PreloadedUserSettings.toBase64(
+ userSettings.userSettings!,
+ ),
+ } as SettingsProtoResponse);
+ },
+);
+
+router.patch(
+ "/",
+ route({
+ requestBody: "SettingsProtoUpdateSchema",
+ responses: {
+ 200: {
+ body: "SettingsProtoUpdateResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const { settings, required_data_version } =
+ req.body as SettingsProtoUpdateSchema;
+ const { atomic } = req.query;
+ const updatedSettings = PreloadedUserSettings.fromBase64(settings);
+
+ const resultObj = await patchUserSettings(
+ req.user_id,
+ updatedSettings,
+ required_data_version,
+ atomic == "true",
+ );
+
+ res.json({
+ settings: PreloadedUserSettings.toBase64(resultObj.settings),
+ out_of_date: resultObj.out_of_date,
+ });
+ },
+);
+
+//#endregion
+//#region JSON
+router.get(
+ "/json",
+ route({
+ responses: {
+ 200: {
+ body: "SettingsProtoJsonResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const userSettings = await UserSettingsProtos.getOrCreate(req.user_id);
+
+ res.json({
+ settings: PreloadedUserSettings.toJson(userSettings.userSettings!),
+ } as SettingsProtoJsonResponse);
+ },
+);
+
+router.patch(
+ "/json",
+ route({
+ requestBody: "SettingsProtoUpdateJsonSchema",
+ responses: {
+ 200: {
+ body: "SettingsProtoUpdateJsonResponse",
+ },
+ },
+ query: {
+ atomic: {
+ type: "boolean",
+ description:
+ "Whether to try to apply the settings update atomically (default false)",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const { settings, required_data_version } =
+ req.body as SettingsProtoUpdateJsonSchema;
+ const { atomic } = req.query;
+ const updatedSettings = PreloadedUserSettings.fromJson(settings);
+
+ const resultObj = await patchUserSettings(
+ req.user_id,
+ updatedSettings,
+ required_data_version,
+ atomic == "true",
+ );
+
+ res.json({
+ settings: PreloadedUserSettings.toJson(resultObj.settings),
+ out_of_date: resultObj.out_of_date,
+ });
+ },
+);
+
+//#endregion
+
+async function patchUserSettings(
+ userId: string,
+ updatedSettings: PreloadedUserSettings,
+ required_data_version: number | undefined,
+ atomic: boolean = false,
+) {
+ const userSettings = await UserSettingsProtos.getOrCreate(userId);
+ let settings = userSettings.userSettings!;
+
+ if (
+ required_data_version &&
+ settings.versions &&
+ settings.versions.dataVersion > required_data_version
+ ) {
+ return {
+ settings: settings,
+ out_of_date: true,
+ };
+ }
+
+ console.log(`Updating user settings for user ${userId} with atomic=${atomic}:`, updatedSettings);
+
+ if (!atomic) {
+ settings = Object.assign(settings, updatedSettings);
+ } else {
+ settings = OrmUtils.mergeDeep(settings, updatedSettings);
+ }
+
+ userSettings.userSettings = settings;
+ await userSettings.save();
+
+ return {
+ settings: settings,
+ out_of_date: false,
+ };
+}
+
+export default router;
diff --git a/src/api/routes/users/@me/settings-proto/2.ts b/src/api/routes/users/@me/settings-proto/2.ts
new file mode 100644
index 00000000..e0cf786f
--- /dev/null
+++ b/src/api/routes/users/@me/settings-proto/2.ts
@@ -0,0 +1,187 @@
+/*
+ Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
+ Copyright (C) 2025 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 { route } from "@spacebar/api";
+import { Request, Response, Router } from "express";
+import {
+ OrmUtils,
+ SettingsProtoJsonResponse,
+ SettingsProtoResponse,
+ SettingsProtoUpdateJsonSchema,
+ SettingsProtoUpdateSchema,
+ UserSettingsProtos,
+} from "@spacebar/util";
+import { FrecencyUserSettings } from "discord-protos";
+
+const router: Router = Router();
+
+//#region Protobuf
+router.get(
+ "/",
+ route({
+ responses: {
+ 200: {
+ body: "SettingsProtoResponse",
+ },
+ },
+ query: {
+ atomic: {
+ type: "boolean",
+ description:
+ "Whether to try to apply the settings update atomically (default false)",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const userSettings = await UserSettingsProtos.getOrCreate(req.user_id);
+
+ res.json({
+ settings: FrecencyUserSettings.toBase64(
+ userSettings.frecencySettings!,
+ ),
+ } as SettingsProtoResponse);
+ },
+);
+
+router.patch(
+ "/",
+ route({
+ requestBody: "SettingsProtoUpdateSchema",
+ responses: {
+ 200: {
+ body: "SettingsProtoUpdateResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const { settings, required_data_version } =
+ req.body as SettingsProtoUpdateSchema;
+ const { atomic } = req.query;
+ const updatedSettings = FrecencyUserSettings.fromBase64(settings);
+
+ const resultObj = await patchUserSettings(
+ req.user_id,
+ updatedSettings,
+ required_data_version,
+ atomic == "true",
+ );
+
+ res.json({
+ settings: FrecencyUserSettings.toBase64(resultObj.settings),
+ out_of_date: resultObj.out_of_date,
+ });
+ },
+);
+
+//#endregion
+//#region JSON
+router.get(
+ "/json",
+ route({
+ responses: {
+ 200: {
+ body: "SettingsProtoJsonResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const userSettings = await UserSettingsProtos.getOrCreate(req.user_id);
+
+ res.json({
+ settings: FrecencyUserSettings.toJson(userSettings.frecencySettings!),
+ } as SettingsProtoJsonResponse);
+ },
+);
+
+router.patch(
+ "/json",
+ route({
+ requestBody: "SettingsProtoUpdateJsonSchema",
+ responses: {
+ 200: {
+ body: "SettingsProtoUpdateJsonResponse",
+ },
+ },
+ query: {
+ atomic: {
+ type: "boolean",
+ description:
+ "Whether to try to apply the settings update atomically (default false)",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const { settings, required_data_version } =
+ req.body as SettingsProtoUpdateJsonSchema;
+ const { atomic } = req.query;
+ const updatedSettings = FrecencyUserSettings.fromJson(settings);
+
+ const resultObj = await patchUserSettings(
+ req.user_id,
+ updatedSettings,
+ required_data_version,
+ atomic == "true",
+ );
+
+ res.json({
+ settings: FrecencyUserSettings.toJson(resultObj.settings),
+ out_of_date: resultObj.out_of_date,
+ });
+ },
+);
+
+//#endregion
+
+async function patchUserSettings(
+ userId: string,
+ updatedSettings: FrecencyUserSettings,
+ required_data_version: number | undefined,
+ atomic: boolean = false,
+) {
+ const userSettings = await UserSettingsProtos.getOrCreate(userId);
+ let settings = userSettings.frecencySettings!;
+
+ if (
+ required_data_version &&
+ settings.versions &&
+ settings.versions.dataVersion > required_data_version
+ ) {
+ return {
+ settings: settings,
+ out_of_date: true,
+ };
+ }
+
+ console.log(`Updating frecency settings for user ${userId} with atomic=${atomic}:`, updatedSettings);
+
+ if (!atomic) {
+ settings = Object.assign(settings, updatedSettings);
+ } else {
+ settings = OrmUtils.mergeDeep(settings, updatedSettings);
+ }
+
+ userSettings.frecencySettings = settings;
+ await userSettings.save();
+
+ return {
+ settings: settings,
+ out_of_date: false,
+ };
+}
+
+export default router;
diff --git a/src/util/entities/UserSettingsProtos.ts b/src/util/entities/UserSettingsProtos.ts
new file mode 100644
index 00000000..b7b8f607
--- /dev/null
+++ b/src/util/entities/UserSettingsProtos.ts
@@ -0,0 +1,170 @@
+/*
+ Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
+ Copyright (C) 2025 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 { Column, Entity, JoinColumn, OneToOne, RelationId } from "typeorm";
+import { BaseClassWithoutId, PrimaryIdColumn } from "./BaseClass";
+import { dbEngine } from "@spacebar/util";
+import { User } from "./User";
+import {
+ FrecencyUserSettings,
+ PreloadedUserSettings,
+ PreloadedUserSettings_LaunchPadMode,
+ PreloadedUserSettings_SwipeRightToLeftMode,
+ PreloadedUserSettings_Theme,
+ PreloadedUserSettings_TimestampHourCycle,
+ PreloadedUserSettings_UIDensity,
+} from "discord-protos";
+
+@Entity({
+ name: "user_settings_protos",
+ engine: dbEngine,
+})
+export class UserSettingsProtos extends BaseClassWithoutId {
+ @OneToOne(() => User, {
+ cascade: true,
+ orphanedRowAction: "delete",
+ eager: false,
+ })
+ @JoinColumn({ name: "user_id" })
+ user: User;
+
+ @PrimaryIdColumn({ type: "text" })
+ user_id: string;
+
+ @Column({ nullable: true, type: String, name: "userSettings" })
+ _userSettings: string | undefined;
+
+ @Column({ nullable: true, type: String, name: "frecencySettings" })
+ _frecencySettings: string | undefined;
+
+ // @Column({nullable: true, type: "simple-json"})
+ // testSettings: {};
+
+ bigintReplacer(_key: string, value: any): any {
+ if (typeof value === "bigint") {
+ return (value as bigint).toString();
+ } else if (value instanceof Uint8Array) {
+ return {
+ __type: "Uint8Array",
+ data: Array.from(value as Uint8Array)
+ .map((b) => b.toString(16).padStart(2, "0"))
+ .join(""),
+ };
+ } else {
+ return value;
+ }
+ }
+
+ bigintReviver(_key: string, value: any): any {
+ if (typeof value === "string" && /^\d+n$/.test(value)) {
+ return BigInt((value as string).slice(0, -1));
+ } else if (
+ typeof value === "object" &&
+ value !== null &&
+ "__type" in value
+ ) {
+ if (value.__type === "Uint8Array" && "data" in value) {
+ return new Uint8Array(
+ value.data
+ .match(/.{1,2}/g)!
+ .map((byte: string) => parseInt(byte, 16)),
+ );
+ }
+ }
+ return value;
+ }
+
+ get userSettings(): PreloadedUserSettings | undefined {
+ if (!this._userSettings) return undefined;
+ return PreloadedUserSettings.fromJson(
+ JSON.parse(this._userSettings, this.bigintReviver),
+ );
+ }
+
+ set userSettings(value: PreloadedUserSettings | undefined) {
+ if (value) {
+ // this._userSettings = JSON.stringify(value, this.bigintReplacer);
+ this._userSettings = PreloadedUserSettings.toJsonString(value);
+ } else {
+ this._userSettings = undefined;
+ }
+ }
+
+ get frecencySettings(): FrecencyUserSettings | undefined {
+ if (!this._frecencySettings) return undefined;
+ return FrecencyUserSettings.fromJson(
+ JSON.parse(this._frecencySettings, this.bigintReviver),
+ );
+ }
+
+ set frecencySettings(value: FrecencyUserSettings | undefined) {
+ if (value) {
+ this._frecencySettings = JSON.stringify(value, this.bigintReplacer);
+ } else {
+ this._frecencySettings = undefined;
+ }
+ }
+
+ static async getOrCreate(user_id: string): Promise {
+ const user = await User.findOneOrFail({
+ where: { id: user_id },
+ select: { settings: true },
+ });
+ let userSettings = await UserSettingsProtos.findOne({
+ where: { user_id },
+ });
+ let modified = false;
+ if (!userSettings) {
+ userSettings = UserSettingsProtos.create({
+ user_id,
+ });
+ modified = true;
+ }
+
+ if (!userSettings.userSettings) {
+ userSettings.userSettings = PreloadedUserSettings.create({
+ ads: {
+ alwaysDeliver: false,
+ },
+ appearance: {
+ developerMode: user.settings?.developer_mode ?? true,
+ theme: PreloadedUserSettings_Theme.DARK,
+ mobileRedesignDisabled: true,
+ launchPadMode:
+ PreloadedUserSettings_LaunchPadMode.LAUNCH_PAD_DISABLED,
+ swipeRightToLeftMode:
+ PreloadedUserSettings_SwipeRightToLeftMode.SWIPE_RIGHT_TO_LEFT_REPLY,
+ timestampHourCycle:
+ PreloadedUserSettings_TimestampHourCycle.AUTO,
+ uiDensity:
+ PreloadedUserSettings_UIDensity.UI_DENSITY_COMPACT,
+ },
+ });
+ modified = true;
+ }
+
+ if (!userSettings.frecencySettings) {
+ userSettings.frecencySettings = FrecencyUserSettings.create({});
+ modified = true;
+ }
+
+ if (modified) userSettings = await userSettings.save();
+
+ return userSettings;
+ }
+}
diff --git a/src/util/entities/index.ts b/src/util/entities/index.ts
index dd967ce5..4c95e83a 100644
--- a/src/util/entities/index.ts
+++ b/src/util/entities/index.ts
@@ -55,6 +55,7 @@ export * from "./TeamMember";
export * from "./Template";
export * from "./User";
export * from "./UserSettings";
+export * from "./UserSettingsProtos";
export * from "./ValidRegistrationTokens";
export * from "./VoiceState";
export * from "./Webhook";
diff --git a/src/util/migration/postgres/1752157979333-UserSettingsProtos.ts b/src/util/migration/postgres/1752157979333-UserSettingsProtos.ts
new file mode 100644
index 00000000..0633e144
--- /dev/null
+++ b/src/util/migration/postgres/1752157979333-UserSettingsProtos.ts
@@ -0,0 +1,17 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class UserSettingsProtos1752157979333 implements MigrationInterface {
+ name = 'UserSettingsProtos1752157979333'
+
+ public async up(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`DROP TABLE IF EXISTS "user_settings_protos"`);
+ await queryRunner.query(`CREATE TABLE "user_settings_protos" ("user_id" character varying NOT NULL, "userSettings" text, "frecencySettings" text, CONSTRAINT "PK_8ff3d1961a48b693810c9f99853" PRIMARY KEY ("user_id"))`);
+ await queryRunner.query(`ALTER TABLE "user_settings_protos" ADD CONSTRAINT "FK_8ff3d1961a48b693810c9f99853" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
+ }
+
+ public async down(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`ALTER TABLE "user_settings_protos" DROP CONSTRAINT "FK_8ff3d1961a48b693810c9f99853"`);
+ await queryRunner.query(`DROP TABLE "user_settings_protos"`);
+ }
+
+}
diff --git a/src/util/schemas/SettingsProtoUpdateSchema.ts b/src/util/schemas/SettingsProtoUpdateSchema.ts
new file mode 100644
index 00000000..2b930bc0
--- /dev/null
+++ b/src/util/schemas/SettingsProtoUpdateSchema.ts
@@ -0,0 +1,47 @@
+/*
+ Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
+ Copyright (C) 2025 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 { JsonValue } from "@protobuf-ts/runtime";
+
+export interface SettingsProtoUpdateSchema {
+ settings: string;
+ required_data_version?: number;
+}
+
+export interface SettingsProtoUpdateJsonSchema {
+ settings: JsonValue;
+ required_data_version?: number;
+}
+
+// TODO: these dont work with schema validation
+// typed JSON schemas:
+// export interface SettingsProtoUpdatePreloadedUserSettingsSchema {
+// settings: PreloadedUserSettings;
+// required_data_version?: number;
+// }
+//
+// export interface SettingsProtoUpdateFrecencyUserSettingsSchema {
+// settings: FrecencyUserSettings;
+// required_data_version?: number;
+// }
+
+// TODO: what is this?
+// export interface SettingsProtoUpdateTestSettingsSchema {
+// settings: {};
+// required_data_version?: number;
+// }
\ No newline at end of file
diff --git a/src/util/schemas/index.ts b/src/util/schemas/index.ts
index a7aaa1fa..4088c158 100644
--- a/src/util/schemas/index.ts
+++ b/src/util/schemas/index.ts
@@ -69,6 +69,7 @@ export * from "./responses";
export * from "./RoleModifySchema";
export * from "./RolePositionUpdateSchema";
export * from "./SelectProtocolSchema";
+export * from "./SettingsProtoUpdateSchema";
export * from "./StreamCreateSchema";
export * from "./StreamDeleteSchema";
export * from "./StreamWatchSchema";
diff --git a/src/util/schemas/responses/SettingsProtoUpdateResponse.ts b/src/util/schemas/responses/SettingsProtoUpdateResponse.ts
new file mode 100644
index 00000000..42f8621a
--- /dev/null
+++ b/src/util/schemas/responses/SettingsProtoUpdateResponse.ts
@@ -0,0 +1,53 @@
+/*
+ Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
+ Copyright (C) 2025 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 { JsonValue } from "@protobuf-ts/runtime";
+
+export interface SettingsProtoResponse {
+ settings: string;
+}
+
+export interface SettingsProtoUpdateResponse extends SettingsProtoResponse {
+ out_of_date?: boolean;
+}
+
+export interface SettingsProtoJsonResponse {
+ settings: JsonValue;
+}
+
+export interface SettingsProtoUpdateJsonResponse extends SettingsProtoJsonResponse {
+ out_of_date?: boolean;
+}
+
+// TODO: these dont work with schemas validation
+// Typed JSON schemas:
+// export interface SettingsProtoUpdatePreloadedUserSettingsJsonResponse {
+// settings: PreloadedUserSettings;
+// out_of_date?: boolean;
+// }
+//
+// export interface SettingsProtoUpdateFrecencyUserSettingsJsonResponse {
+// settings: FrecencyUserSettings;
+// out_of_date?: boolean;
+// }
+
+// TODO: what is this?
+// export interface SettingsProtoUpdateTestSettingsJsonResponse {
+// settings: {};
+// out_of_date?: boolean;
+// }
diff --git a/src/util/schemas/responses/index.ts b/src/util/schemas/responses/index.ts
index 29537cf7..8949924b 100644
--- a/src/util/schemas/responses/index.ts
+++ b/src/util/schemas/responses/index.ts
@@ -47,6 +47,7 @@ export * from "./LocationMetadataResponse";
export * from "./MemberJoinGuildResponse";
export * from "./OAuthAuthorizeResponse";
export * from "./RefreshUrlsResponse";
+export * from "./SettingsProtoUpdateResponse";
export * from "./TeamListResponse";
export * from "./Tenor";
export * from "./TokenResponse";