diff --git a/assets/openapi.json b/assets/openapi.json
index 95a8807f..45a151ba 100644
--- a/assets/openapi.json
+++ b/assets/openapi.json
@@ -3670,6 +3670,75 @@
"id"
]
},
+ "RoleResponse": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "description": "A Twitter-like snowflake, except the epoch is 2015-01-01T00:00:00.000Z\n```\nIf we have a snowflake '266241948824764416' we can represent it as binary:\n\n64 22 17 12 0\n 000000111011000111100001101001000101000000 00001 00000 000000000000\n number of ms since Discord epoch worker pid increment\n```",
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string",
+ "nullable": true
+ },
+ "color": {
+ "type": "integer"
+ },
+ "colors": {
+ "$ref": "#/components/schemas/RoleColors"
+ },
+ "hoist": {
+ "type": "boolean"
+ },
+ "icon": {
+ "type": "string",
+ "nullable": true
+ },
+ "unicode_emoji": {
+ "type": "string",
+ "nullable": true
+ },
+ "position": {
+ "type": "integer"
+ },
+ "permissions": {
+ "type": "string"
+ },
+ "managed": {
+ "type": "boolean"
+ },
+ "mentionable": {
+ "type": "boolean"
+ },
+ "flags": {
+ "type": "integer"
+ },
+ "tags": {
+ "$ref": "#/components/schemas/RoleTags"
+ }
+ },
+ "required": [
+ "color",
+ "colors",
+ "description",
+ "hoist",
+ "id",
+ "managed",
+ "mentionable",
+ "name",
+ "permissions",
+ "position"
+ ]
+ },
+ "RoleListResponse": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/RoleResponse"
+ }
+ },
"StickersResponse": {
"type": "array",
"items": {
@@ -5097,12 +5166,6 @@
"widget_enabled"
]
},
- "APIRoleArray": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/Role"
- }
- },
"APITemplateArray": {
"type": "array",
"items": {
@@ -14061,6 +14124,35 @@
3
]
},
+ "RoleTags": {
+ "type": "object",
+ "properties": {
+ "bot_id": {
+ "description": "A Twitter-like snowflake, except the epoch is 2015-01-01T00:00:00.000Z\n```\nIf we have a snowflake '266241948824764416' we can represent it as binary:\n\n64 22 17 12 0\n 000000111011000111100001101001000101000000 00001 00000 000000000000\n number of ms since Discord epoch worker pid increment\n```",
+ "type": "string"
+ },
+ "integration_id": {
+ "description": "A Twitter-like snowflake, except the epoch is 2015-01-01T00:00:00.000Z\n```\nIf we have a snowflake '266241948824764416' we can represent it as binary:\n\n64 22 17 12 0\n 000000111011000111100001101001000101000000 00001 00000 000000000000\n number of ms since Discord epoch worker pid increment\n```",
+ "type": "string"
+ },
+ "subscription_listing_id": {
+ "description": "A Twitter-like snowflake, except the epoch is 2015-01-01T00:00:00.000Z\n```\nIf we have a snowflake '266241948824764416' we can represent it as binary:\n\n64 22 17 12 0\n 000000111011000111100001101001000101000000 00001 00000 000000000000\n number of ms since Discord epoch worker pid increment\n```",
+ "type": "string"
+ },
+ "premium_subscriber": {
+ "type": "boolean",
+ "nullable": true
+ },
+ "available_for_purchase": {
+ "type": "boolean",
+ "nullable": true
+ },
+ "guild_connections": {
+ "type": "boolean",
+ "nullable": true
+ }
+ }
+ },
"DmChannelDTO": {
"type": "object",
"properties": {
@@ -20826,7 +20918,7 @@
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/APIRoleArray"
+ "$ref": "#/components/schemas/RoleListResponse"
}
}
}
diff --git a/assets/schemas.json b/assets/schemas.json
index 9506fab1..b82fe518 100644
--- a/assets/schemas.json
+++ b/assets/schemas.json
@@ -3893,6 +3893,84 @@
],
"$schema": "http://json-schema.org/draft-07/schema#"
},
+ "RoleResponse": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "description": "A Twitter-like snowflake, except the epoch is 2015-01-01T00:00:00.000Z\n```\nIf we have a snowflake '266241948824764416' we can represent it as binary:\n\n64 22 17 12 0\n 000000111011000111100001101001000101000000 00001 00000 000000000000\n number of ms since Discord epoch worker pid increment\n```",
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "description": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "color": {
+ "type": "integer"
+ },
+ "colors": {
+ "$ref": "#/definitions/RoleColors"
+ },
+ "hoist": {
+ "type": "boolean"
+ },
+ "icon": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "unicode_emoji": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "position": {
+ "type": "integer"
+ },
+ "permissions": {
+ "type": "string"
+ },
+ "managed": {
+ "type": "boolean"
+ },
+ "mentionable": {
+ "type": "boolean"
+ },
+ "flags": {
+ "type": "integer"
+ },
+ "tags": {
+ "$ref": "#/definitions/RoleTags"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "color",
+ "colors",
+ "description",
+ "hoist",
+ "id",
+ "managed",
+ "mentionable",
+ "name",
+ "permissions",
+ "position"
+ ],
+ "$schema": "http://json-schema.org/draft-07/schema#"
+ },
+ "RoleListResponse": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/RoleResponse"
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+ },
"StickersResponse": {
"type": "array",
"items": {
@@ -5399,13 +5477,6 @@
],
"$schema": "http://json-schema.org/draft-07/schema#"
},
- "APIRoleArray": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/Role"
- },
- "$schema": "http://json-schema.org/draft-07/schema#"
- },
"APITemplateArray": {
"type": "array",
"items": {
@@ -15024,6 +15095,43 @@
],
"$schema": "http://json-schema.org/draft-07/schema#"
},
+ "RoleTags": {
+ "type": "object",
+ "properties": {
+ "bot_id": {
+ "description": "A Twitter-like snowflake, except the epoch is 2015-01-01T00:00:00.000Z\n```\nIf we have a snowflake '266241948824764416' we can represent it as binary:\n\n64 22 17 12 0\n 000000111011000111100001101001000101000000 00001 00000 000000000000\n number of ms since Discord epoch worker pid increment\n```",
+ "type": "string"
+ },
+ "integration_id": {
+ "description": "A Twitter-like snowflake, except the epoch is 2015-01-01T00:00:00.000Z\n```\nIf we have a snowflake '266241948824764416' we can represent it as binary:\n\n64 22 17 12 0\n 000000111011000111100001101001000101000000 00001 00000 000000000000\n number of ms since Discord epoch worker pid increment\n```",
+ "type": "string"
+ },
+ "subscription_listing_id": {
+ "description": "A Twitter-like snowflake, except the epoch is 2015-01-01T00:00:00.000Z\n```\nIf we have a snowflake '266241948824764416' we can represent it as binary:\n\n64 22 17 12 0\n 000000111011000111100001101001000101000000 00001 00000 000000000000\n number of ms since Discord epoch worker pid increment\n```",
+ "type": "string"
+ },
+ "premium_subscriber": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "available_for_purchase": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "guild_connections": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "$schema": "http://json-schema.org/draft-07/schema#"
+ },
"DmChannelDTO": {
"type": "object",
"properties": {
diff --git a/src/api/routes/guilds/#guild_id/roles/index.ts b/src/api/routes/guilds/#guild_id/roles/index.ts
index 4cb82663..5f792222 100644
--- a/src/api/routes/guilds/#guild_id/roles/index.ts
+++ b/src/api/routes/guilds/#guild_id/roles/index.ts
@@ -119,7 +119,7 @@ router.patch(
permission: "MANAGE_ROLES",
responses: {
200: {
- body: "APIRoleArray",
+ body: "RoleListResponse",
},
400: {
body: "APIErrorResponse",
diff --git a/src/schemas/api/guilds/Role.ts b/src/schemas/api/guilds/Role.ts
index 2f32e5d7..fd3440e6 100644
--- a/src/schemas/api/guilds/Role.ts
+++ b/src/schemas/api/guilds/Role.ts
@@ -1,3 +1,44 @@
+/*
+ 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 <https://www.gnu.org/licenses/>.
+*/
+
+import { Snowflake } from "../../Identifiers";
+
+export interface RoleResponse {
+ id: Snowflake;
+ name: string;
+ description: string | null;
+ // @deprecated
+ color: number;
+ colors: RoleColors;
+ hoist: boolean;
+ icon?: string | null;
+ unicode_emoji?: string | null;
+ position: number;
+ // @format number
+ permissions: string;
+ managed: boolean;
+ mentionable: boolean;
+ flags?: number;
+ tags?: RoleTags; // unused currently
+}
+
+export type RoleListResponse = RoleResponse[];
+
export class RoleColors {
primary_color: number;
secondary_color: number | undefined; // only used for "holographic" and "gradient" styles
@@ -11,3 +52,23 @@ export class RoleColors {
};
}
}
+
+export class RoleTags {
+ bot_id?: Snowflake;
+ integration_id?: Snowflake;
+ subscription_listing_id?: Snowflake;
+ // ??? https://github.com/discord-userdoccers/discord-userdoccers/issues/576 - in other words, types are currently unknown
+ premium_subscriber?: boolean | null;
+ available_for_purchase?: boolean | null;
+ guild_connections?: boolean | null;
+
+ toJSON(): RoleTags {
+ return {
+ ...this,
+ // "forward compatibility"
+ premium_subscriber: this.premium_subscriber ? null : undefined,
+ available_for_purchase: this.available_for_purchase ? null : undefined,
+ guild_connections: this.subscription_listing_id ? null : undefined,
+ };
+ }
+}
diff --git a/src/schemas/responses/TypedResponses.ts b/src/schemas/responses/TypedResponses.ts
index 692487b0..e0413a72 100644
--- a/src/schemas/responses/TypedResponses.ts
+++ b/src/schemas/responses/TypedResponses.ts
@@ -20,8 +20,7 @@
import { GeneralConfiguration, LimitsConfiguration } from "../../util/config/types";
import { DmChannelDTO } from "../../util/dtos";
// TODO: remove entity imports
-import { Application, BackupCode, Categories, Channel, Guild, Invite, Member, Message, Role, Template, Webhook } from "@spacebar/database";
-import { GuildVoiceRegion } from "./GuildVoiceRegionsResponse";
+import { Application, BackupCode, Categories, Channel, Guild, Invite, Member, Message, Template, Webhook } from "@spacebar/database";
import { GuildCreateResponse, PrivateUser, PublicMember, PublicUser } from "@spacebar/schemas";
// TODO: remove this entire file!
@@ -54,7 +53,6 @@ export interface APIGuildWithJoinedAt extends GuildCreateResponse {
joined_at: string;
}
-export type APIRoleArray = Role[];
export type APITemplateArray = Template[];
export type APILimitsConfiguration = LimitsConfiguration;
|