diff --git a/assets/openapi.json b/assets/openapi.json
index 62b53f9a5..463269130 100644
--- a/assets/openapi.json
+++ b/assets/openapi.json
@@ -1550,6 +1550,12 @@
"$ref": "#/components/schemas/PublicMember"
}
},
+ "PaymentSourceListResponse": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/PaymentSource"
+ }
+ },
"PartialRelationshipSchema": {
"type": "object",
"properties": {
@@ -3124,6 +3130,218 @@
"verified"
]
},
+ "Tag": {
+ "type": "object",
+ "properties": {
+ "channel_id": {
+ "type": "string"
+ },
+ "channel": {
+ "$ref": "#/components/schemas/Channel"
+ },
+ "name": {
+ "type": "string"
+ },
+ "moderated": {
+ "type": "boolean",
+ "default": false
+ },
+ "emoji_id": {
+ "type": "string"
+ },
+ "emoji_name": {
+ "type": "string"
+ },
+ "id": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "channel",
+ "channel_id",
+ "id",
+ "moderated",
+ "name"
+ ]
+ },
+ "Channel": {
+ "type": "object",
+ "properties": {
+ "created_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "name": {
+ "type": "string"
+ },
+ "icon": {
+ "type": "string",
+ "nullable": true
+ },
+ "type": {
+ "$ref": "#/components/schemas/ChannelType"
+ },
+ "recipients": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Recipient"
+ }
+ },
+ "thread_members": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ThreadMember"
+ }
+ },
+ "last_message_id": {
+ "type": "string"
+ },
+ "guild_id": {
+ "type": "string"
+ },
+ "guild": {
+ "$ref": "#/components/schemas/Guild"
+ },
+ "parent_id": {
+ "type": "string",
+ "nullable": true
+ },
+ "parent": {
+ "$ref": "#/components/schemas/Channel"
+ },
+ "owner_id": {
+ "type": "string"
+ },
+ "owner": {
+ "$ref": "#/components/schemas/User"
+ },
+ "last_pin_timestamp": {
+ "anyOf": [
+ {
+ "type": "string",
+ "format": "date-time"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "default_auto_archive_duration": {
+ "type": "integer"
+ },
+ "permission_overwrites": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ChannelPermissionOverwrite"
+ }
+ },
+ "video_quality_mode": {
+ "type": "integer"
+ },
+ "bitrate": {
+ "type": "integer"
+ },
+ "user_limit": {
+ "type": "integer"
+ },
+ "nsfw": {
+ "type": "boolean",
+ "default": false
+ },
+ "rate_limit_per_user": {
+ "type": "integer"
+ },
+ "topic": {
+ "type": "string"
+ },
+ "invites": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Invite"
+ }
+ },
+ "retention_policy_id": {
+ "type": "string"
+ },
+ "messages": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Message"
+ }
+ },
+ "voice_states": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/VoiceState"
+ }
+ },
+ "read_states": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ReadState"
+ }
+ },
+ "webhooks": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Webhook"
+ }
+ },
+ "flags": {
+ "type": "integer",
+ "default": 0
+ },
+ "default_thread_rate_limit_per_user": {
+ "type": "integer",
+ "default": 0
+ },
+ "thread_metadata": {
+ "$ref": "#/components/schemas/ThreadMetadata"
+ },
+ "member_count": {
+ "type": "integer"
+ },
+ "message_count": {
+ "type": "integer"
+ },
+ "total_message_sent": {
+ "type": "integer"
+ },
+ "available_tags": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Tag"
+ }
+ },
+ "applied_tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "status": {
+ "type": "string",
+ "nullable": true
+ },
+ "position": {
+ "description": "Must be calculated Channel.calculatePosition",
+ "type": "integer"
+ },
+ "id": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "created_at",
+ "flags",
+ "id",
+ "nsfw",
+ "owner",
+ "parent_id",
+ "position",
+ "type"
+ ]
+ },
"PreloadMessagesResponseSchema": {
"type": "array",
"items": {
@@ -6115,6 +6333,17 @@
"thread_ids"
]
},
+ "PostDataResponse": {
+ "type": "object",
+ "properties": {
+ "threads": {
+ "$ref": "#/components/schemas/Record%3Cstring%2CPostData%3E"
+ }
+ },
+ "required": [
+ "threads"
+ ]
+ },
"TagCreateSchema": {
"type": "object",
"properties": {
@@ -6614,6 +6843,12 @@
"id"
]
},
+ "PublicThreadMembersResponse": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/PublicThreadMember"
+ }
+ },
"WebhookCreateResponse": {
"type": "object",
"properties": {
@@ -8139,6 +8374,12 @@
"$ref": "#/components/schemas/VoiceRegionResponse"
}
},
+ "InviteListResponse": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/PublicInvite"
+ }
+ },
"FieldErrorResponse": {
"type": "object",
"properties": {
@@ -8158,12 +8399,6 @@
"message"
]
},
- "InviteListResponse": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/PublicInvite"
- }
- },
"RouteResponse": {
"type": "object",
"properties": {
@@ -10395,184 +10630,6 @@
"widget_enabled"
]
},
- "Channel": {
- "type": "object",
- "properties": {
- "created_at": {
- "type": "string",
- "format": "date-time"
- },
- "name": {
- "type": "string"
- },
- "icon": {
- "type": "string",
- "nullable": true
- },
- "type": {
- "$ref": "#/components/schemas/ChannelType"
- },
- "recipients": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/Recipient"
- }
- },
- "thread_members": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/ThreadMember"
- }
- },
- "last_message_id": {
- "type": "string"
- },
- "guild_id": {
- "type": "string"
- },
- "guild": {
- "$ref": "#/components/schemas/Guild"
- },
- "parent_id": {
- "type": "string",
- "nullable": true
- },
- "parent": {
- "$ref": "#/components/schemas/Channel"
- },
- "owner_id": {
- "type": "string"
- },
- "owner": {
- "$ref": "#/components/schemas/User"
- },
- "last_pin_timestamp": {
- "anyOf": [
- {
- "type": "string",
- "format": "date-time"
- },
- {
- "type": "null"
- }
- ]
- },
- "default_auto_archive_duration": {
- "type": "integer"
- },
- "permission_overwrites": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/ChannelPermissionOverwrite"
- }
- },
- "video_quality_mode": {
- "type": "integer"
- },
- "bitrate": {
- "type": "integer"
- },
- "user_limit": {
- "type": "integer"
- },
- "nsfw": {
- "type": "boolean",
- "default": false
- },
- "rate_limit_per_user": {
- "type": "integer"
- },
- "topic": {
- "type": "string"
- },
- "invites": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/Invite"
- }
- },
- "retention_policy_id": {
- "type": "string"
- },
- "messages": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/Message"
- }
- },
- "voice_states": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/VoiceState"
- }
- },
- "read_states": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/ReadState"
- }
- },
- "webhooks": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/Webhook"
- }
- },
- "flags": {
- "type": "integer",
- "default": 0
- },
- "default_thread_rate_limit_per_user": {
- "type": "integer",
- "default": 0
- },
- "thread_metadata": {
- "$ref": "#/components/schemas/ThreadMetadata"
- },
- "member_count": {
- "type": "integer"
- },
- "message_count": {
- "type": "integer"
- },
- "total_message_sent": {
- "type": "integer"
- },
- "available_tags": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/Tag"
- }
- },
- "applied_tags": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "status": {
- "type": "string",
- "nullable": true
- },
- "position": {
- "description": "Must be calculated Channel.calculatePosition",
- "type": "integer"
- },
- "id": {
- "type": "string"
- }
- },
- "required": [
- "created_at",
- "flags",
- "id",
- "nsfw",
- "owner",
- "parent_id",
- "position",
- "type"
- ]
- },
"ChannelType": {
"type": "number",
"enum": [
@@ -11531,7 +11588,7 @@
"type": "boolean"
},
"mute_config": {
- "$ref": "#/components/schemas/ThreadMemberMuteConfig"
+ "$ref": "#/components/schemas/MuteConfig"
},
"flags": {
"$ref": "#/components/schemas/ThreadMemberFlags"
@@ -11872,18 +11929,6 @@
"selected_time_window"
]
},
- "ThreadMemberMuteConfig": {
- "type": "object",
- "properties": {
- "end_time": {
- "type": "string",
- "format": "date-time"
- },
- "selected_time_window": {
- "type": "integer"
- }
- }
- },
"ThreadMemberFlags": {
"type": "number",
"enum": [
@@ -14207,40 +14252,6 @@
"locked"
]
},
- "Tag": {
- "type": "object",
- "properties": {
- "channel_id": {
- "type": "string"
- },
- "channel": {
- "$ref": "#/components/schemas/Channel"
- },
- "name": {
- "type": "string"
- },
- "moderated": {
- "type": "boolean",
- "default": false
- },
- "emoji_id": {
- "type": "string"
- },
- "emoji_name": {
- "type": "string"
- },
- "id": {
- "type": "string"
- }
- },
- "required": [
- "channel",
- "channel_id",
- "id",
- "moderated",
- "name"
- ]
- },
"Ban": {
"type": "object",
"properties": {
@@ -14551,6 +14562,153 @@
"username"
]
},
+ "PaymentSource": {
+ "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"
+ },
+ "brand": {
+ "type": "string"
+ },
+ "country": {
+ "type": "string"
+ },
+ "last_4": {
+ "type": "string"
+ },
+ "billing_address": {
+ "$ref": "#/components/schemas/BillingAddress"
+ },
+ "type": {
+ "$ref": "#/components/schemas/PaymentSourceType"
+ },
+ "payment_gateway": {
+ "$ref": "#/components/schemas/PaymentGateway"
+ },
+ "payment_gateway_source_id": {
+ "type": "string"
+ },
+ "default": {
+ "type": "boolean"
+ },
+ "invalid": {
+ "type": "boolean"
+ },
+ "flags": {
+ "$ref": "#/components/schemas/PaymentSourceFlags"
+ },
+ "deleted_at": {
+ "type": "string",
+ "nullable": true
+ },
+ "expires_month": {
+ "type": "integer"
+ },
+ "expires_year": {
+ "type": "integer"
+ },
+ "email": {
+ "type": "string"
+ },
+ "bank": {
+ "type": "string"
+ },
+ "username": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "billing_address",
+ "default",
+ "deleted_at",
+ "flags",
+ "id",
+ "invalid",
+ "payment_gateway",
+ "type"
+ ]
+ },
+ "BillingAddress": {
+ "type": "object",
+ "properties": {
+ "line_1": {
+ "type": "string"
+ },
+ "line_2": {
+ "type": "string",
+ "nullable": true
+ },
+ "name": {
+ "type": "string"
+ },
+ "postal_code": {
+ "type": "string"
+ },
+ "city": {
+ "type": "string"
+ },
+ "state": {
+ "type": "string"
+ },
+ "country": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "city",
+ "country",
+ "line_1",
+ "name"
+ ]
+ },
+ "PaymentSourceType": {
+ "type": "number",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19
+ ]
+ },
+ "PaymentGateway": {
+ "type": "number",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10
+ ]
+ },
+ "PaymentSourceFlags": {
+ "type": "number",
+ "enum": [
+ 1,
+ 2
+ ]
+ },
"EmojiGuild": {
"type": "object",
"properties": {
@@ -15095,7 +15253,7 @@
"$ref": "#/components/schemas/ThreadMetadata"
},
"member": {
- "$ref": "#/components/schemas/ThreadMember"
+ "$ref": "#/components/schemas/PublicThreadMember"
},
"default_auto_archive_duration": {
"type": "integer",
@@ -15174,6 +15332,45 @@
"type"
]
},
+ "PublicThreadMember": {
+ "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"
+ },
+ "user_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"
+ },
+ "join_timestamp": {
+ "type": "string"
+ },
+ "flags": {
+ "$ref": "#/components/schemas/ThreadMemberFlags"
+ },
+ "muted": {
+ "type": "boolean"
+ },
+ "mute_config": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/MuteConfig"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "member": {
+ "$ref": "#/components/schemas/PublicMember"
+ }
+ },
+ "required": [
+ "flags",
+ "join_timestamp"
+ ]
+ },
"MessageActivity": {
"type": "object",
"properties": {
@@ -15231,6 +15428,40 @@
}
}
},
+ "Tag_1": {
+ "type": "object",
+ "properties": {
+ "channel_id": {
+ "type": "string"
+ },
+ "channel": {
+ "$ref": "#/components/schemas/Channel"
+ },
+ "name": {
+ "type": "string"
+ },
+ "moderated": {
+ "type": "boolean",
+ "default": false
+ },
+ "emoji_id": {
+ "type": "string"
+ },
+ "emoji_name": {
+ "type": "string"
+ },
+ "id": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "channel",
+ "channel_id",
+ "id",
+ "moderated",
+ "name"
+ ]
+ },
"Potion": {
"type": "object",
"properties": {
@@ -15634,13 +15865,29 @@
"properties": {
"maxEmojis": {
"type": "integer",
- "default": 100
+ "default": 1000
+ },
+ "commandLimits": {
+ "$ref": "#/components/schemas/CommandLimits"
}
},
"required": [
+ "commandLimits",
"maxEmojis"
]
},
+ "CommandLimits": {
+ "type": "object",
+ "properties": {
+ "maxNameLength": {
+ "type": "integer",
+ "default": 32
+ }
+ },
+ "required": [
+ "maxNameLength"
+ ]
+ },
"UserLimits": {
"type": "object",
"properties": {
@@ -17117,9 +17364,6 @@
}
}
},
- "ErrorList": {
- "type": "object"
- },
"PublicInvite": {
"type": "object",
"properties": {
@@ -17389,6 +17633,9 @@
2,
3
]
+ },
+ "ErrorList": {
+ "type": "object"
}
}
},
@@ -19826,8 +20073,15 @@
}
],
"responses": {
- "default": {
- "description": "No description available"
+ "200": {
+ "description": "",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PaymentSourceListResponse"
+ }
+ }
+ }
}
},
"tags": [
@@ -19841,8 +20095,15 @@
}
],
"responses": {
- "default": {
- "description": "No description available"
+ "200": {
+ "description": "",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PaymentSourceListResponse"
+ }
+ }
+ }
}
},
"tags": [
@@ -19858,8 +20119,15 @@
}
],
"responses": {
- "default": {
- "description": "No description available"
+ "200": {
+ "description": "",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PaymentSource"
+ }
+ }
+ }
}
},
"parameters": [
@@ -19884,8 +20152,15 @@
}
],
"responses": {
- "default": {
- "description": "No description available"
+ "200": {
+ "description": "",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PaymentSourceListResponse"
+ }
+ }
+ }
}
},
"parameters": [
@@ -27482,7 +27757,14 @@
],
"responses": {
"200": {
- "description": "No description available"
+ "description": "",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PublicThreadMembersResponse"
+ }
+ }
+ }
},
"403": {
"description": "No description available"
@@ -27911,7 +28193,14 @@
},
"responses": {
"200": {
- "description": "No description available"
+ "description": "",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PostDataResponse"
+ }
+ }
+ }
},
"403": {
"description": "No description available"
@@ -29413,7 +29702,7 @@
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/Invite"
+ "$ref": "#/components/schemas/PublicInvite"
}
}
}
diff --git a/assets/schemas.json b/assets/schemas.json
index 6891629d1..f7b875759 100644
--- a/assets/schemas.json
+++ b/assets/schemas.json
@@ -1643,6 +1643,13 @@
},
"$schema": "http://json-schema.org/draft-07/schema#"
},
+ "PaymentSourceListResponse": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/PaymentSource"
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+ },
"PartialRelationshipSchema": {
"type": "object",
"properties": {
@@ -3342,6 +3349,228 @@
"items": {
"$ref": "#/definitions/PublicMessage"
},
+ "definitions": {
+ "Tag": {
+ "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"
+ },
+ "moderated": {
+ "type": "boolean"
+ },
+ "emoji_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "emoji_name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "emoji_id",
+ "emoji_name",
+ "id",
+ "moderated",
+ "name"
+ ]
+ },
+ "Channel": {
+ "type": "object",
+ "properties": {
+ "created_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "name": {
+ "type": "string"
+ },
+ "icon": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "type": {
+ "$ref": "#/definitions/ChannelType"
+ },
+ "recipients": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Recipient"
+ }
+ },
+ "thread_members": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/ThreadMember"
+ }
+ },
+ "last_message_id": {
+ "type": "string"
+ },
+ "guild_id": {
+ "type": "string"
+ },
+ "guild": {
+ "$ref": "#/definitions/Guild"
+ },
+ "parent_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "parent": {
+ "$ref": "#/definitions/Channel"
+ },
+ "owner_id": {
+ "type": "string"
+ },
+ "owner": {
+ "$ref": "#/definitions/User"
+ },
+ "last_pin_timestamp": {
+ "anyOf": [
+ {
+ "type": "string",
+ "format": "date-time"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "default_auto_archive_duration": {
+ "type": "integer"
+ },
+ "permission_overwrites": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/ChannelPermissionOverwrite"
+ }
+ },
+ "video_quality_mode": {
+ "type": "integer"
+ },
+ "bitrate": {
+ "type": "integer"
+ },
+ "user_limit": {
+ "type": "integer"
+ },
+ "nsfw": {
+ "type": "boolean",
+ "default": false
+ },
+ "rate_limit_per_user": {
+ "type": "integer"
+ },
+ "topic": {
+ "type": "string"
+ },
+ "invites": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Invite"
+ }
+ },
+ "retention_policy_id": {
+ "type": "string"
+ },
+ "messages": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Message"
+ }
+ },
+ "voice_states": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/VoiceState"
+ }
+ },
+ "read_states": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/ReadState"
+ }
+ },
+ "webhooks": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Webhook"
+ }
+ },
+ "flags": {
+ "type": "integer",
+ "default": 0
+ },
+ "default_thread_rate_limit_per_user": {
+ "type": "integer",
+ "default": 0
+ },
+ "thread_metadata": {
+ "$ref": "#/definitions/ThreadMetadata"
+ },
+ "member_count": {
+ "type": "integer"
+ },
+ "message_count": {
+ "type": "integer"
+ },
+ "total_message_sent": {
+ "type": "integer"
+ },
+ "available_tags": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Tag_1"
+ }
+ },
+ "applied_tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "status": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "position": {
+ "description": "Must be calculated Channel.calculatePosition",
+ "type": "integer"
+ },
+ "id": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "created_at",
+ "flags",
+ "id",
+ "nsfw",
+ "owner",
+ "parent_id",
+ "position",
+ "type"
+ ]
+ }
+ },
"$schema": "http://json-schema.org/draft-07/schema#"
},
"RefreshUrlsResponse": {
@@ -6556,6 +6785,19 @@
],
"$schema": "http://json-schema.org/draft-07/schema#"
},
+ "PostDataResponse": {
+ "type": "object",
+ "properties": {
+ "threads": {
+ "$ref": "#/definitions/Record%3Cstring%2CPostData%3E"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "threads"
+ ],
+ "$schema": "http://json-schema.org/draft-07/schema#"
+ },
"TagCreateSchema": {
"type": "object",
"properties": {
@@ -6723,6 +6965,228 @@
"items": {
"$ref": "#/definitions/PublicMessage"
},
+ "definitions": {
+ "Tag": {
+ "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"
+ },
+ "moderated": {
+ "type": "boolean"
+ },
+ "emoji_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "emoji_name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "emoji_id",
+ "emoji_name",
+ "id",
+ "moderated",
+ "name"
+ ]
+ },
+ "Channel": {
+ "type": "object",
+ "properties": {
+ "created_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "name": {
+ "type": "string"
+ },
+ "icon": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "type": {
+ "$ref": "#/definitions/ChannelType"
+ },
+ "recipients": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Recipient"
+ }
+ },
+ "thread_members": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/ThreadMember"
+ }
+ },
+ "last_message_id": {
+ "type": "string"
+ },
+ "guild_id": {
+ "type": "string"
+ },
+ "guild": {
+ "$ref": "#/definitions/Guild"
+ },
+ "parent_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "parent": {
+ "$ref": "#/definitions/Channel"
+ },
+ "owner_id": {
+ "type": "string"
+ },
+ "owner": {
+ "$ref": "#/definitions/User"
+ },
+ "last_pin_timestamp": {
+ "anyOf": [
+ {
+ "type": "string",
+ "format": "date-time"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "default_auto_archive_duration": {
+ "type": "integer"
+ },
+ "permission_overwrites": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/ChannelPermissionOverwrite"
+ }
+ },
+ "video_quality_mode": {
+ "type": "integer"
+ },
+ "bitrate": {
+ "type": "integer"
+ },
+ "user_limit": {
+ "type": "integer"
+ },
+ "nsfw": {
+ "type": "boolean",
+ "default": false
+ },
+ "rate_limit_per_user": {
+ "type": "integer"
+ },
+ "topic": {
+ "type": "string"
+ },
+ "invites": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Invite"
+ }
+ },
+ "retention_policy_id": {
+ "type": "string"
+ },
+ "messages": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Message"
+ }
+ },
+ "voice_states": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/VoiceState"
+ }
+ },
+ "read_states": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/ReadState"
+ }
+ },
+ "webhooks": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Webhook"
+ }
+ },
+ "flags": {
+ "type": "integer",
+ "default": 0
+ },
+ "default_thread_rate_limit_per_user": {
+ "type": "integer",
+ "default": 0
+ },
+ "thread_metadata": {
+ "$ref": "#/definitions/ThreadMetadata"
+ },
+ "member_count": {
+ "type": "integer"
+ },
+ "message_count": {
+ "type": "integer"
+ },
+ "total_message_sent": {
+ "type": "integer"
+ },
+ "available_tags": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Tag_1"
+ }
+ },
+ "applied_tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "status": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "position": {
+ "description": "Must be calculated Channel.calculatePosition",
+ "type": "integer"
+ },
+ "id": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "created_at",
+ "flags",
+ "id",
+ "nsfw",
+ "owner",
+ "parent_id",
+ "position",
+ "type"
+ ]
+ }
+ },
"$schema": "http://json-schema.org/draft-07/schema#"
},
"PollUserAnswersSchema": {
@@ -6879,6 +7343,228 @@
"type",
"version"
],
+ "definitions": {
+ "Tag": {
+ "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"
+ },
+ "moderated": {
+ "type": "boolean"
+ },
+ "emoji_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "emoji_name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "emoji_id",
+ "emoji_name",
+ "id",
+ "moderated",
+ "name"
+ ]
+ },
+ "Channel": {
+ "type": "object",
+ "properties": {
+ "created_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "name": {
+ "type": "string"
+ },
+ "icon": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "type": {
+ "$ref": "#/definitions/ChannelType"
+ },
+ "recipients": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Recipient"
+ }
+ },
+ "thread_members": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/ThreadMember"
+ }
+ },
+ "last_message_id": {
+ "type": "string"
+ },
+ "guild_id": {
+ "type": "string"
+ },
+ "guild": {
+ "$ref": "#/definitions/Guild"
+ },
+ "parent_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "parent": {
+ "$ref": "#/definitions/Channel"
+ },
+ "owner_id": {
+ "type": "string"
+ },
+ "owner": {
+ "$ref": "#/definitions/User"
+ },
+ "last_pin_timestamp": {
+ "anyOf": [
+ {
+ "type": "string",
+ "format": "date-time"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "default_auto_archive_duration": {
+ "type": "integer"
+ },
+ "permission_overwrites": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/ChannelPermissionOverwrite"
+ }
+ },
+ "video_quality_mode": {
+ "type": "integer"
+ },
+ "bitrate": {
+ "type": "integer"
+ },
+ "user_limit": {
+ "type": "integer"
+ },
+ "nsfw": {
+ "type": "boolean",
+ "default": false
+ },
+ "rate_limit_per_user": {
+ "type": "integer"
+ },
+ "topic": {
+ "type": "string"
+ },
+ "invites": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Invite"
+ }
+ },
+ "retention_policy_id": {
+ "type": "string"
+ },
+ "messages": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Message"
+ }
+ },
+ "voice_states": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/VoiceState"
+ }
+ },
+ "read_states": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/ReadState"
+ }
+ },
+ "webhooks": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Webhook"
+ }
+ },
+ "flags": {
+ "type": "integer",
+ "default": 0
+ },
+ "default_thread_rate_limit_per_user": {
+ "type": "integer",
+ "default": 0
+ },
+ "thread_metadata": {
+ "$ref": "#/definitions/ThreadMetadata"
+ },
+ "member_count": {
+ "type": "integer"
+ },
+ "message_count": {
+ "type": "integer"
+ },
+ "total_message_sent": {
+ "type": "integer"
+ },
+ "available_tags": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Tag_1"
+ }
+ },
+ "applied_tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "status": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "position": {
+ "description": "Must be calculated Channel.calculatePosition",
+ "type": "integer"
+ },
+ "id": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "created_at",
+ "flags",
+ "id",
+ "nsfw",
+ "owner",
+ "parent_id",
+ "position",
+ "type"
+ ]
+ }
+ },
"$schema": "http://json-schema.org/draft-07/schema#"
},
"ApplicationCreateSchema": {
@@ -7089,6 +7775,13 @@
],
"$schema": "http://json-schema.org/draft-07/schema#"
},
+ "PublicThreadMembersResponse": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/PublicThreadMember"
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+ },
"WebhookCreateResponse": {
"type": "object",
"properties": {
@@ -7244,6 +7937,43 @@
"users",
"webhooks"
],
+ "definitions": {
+ "Tag": {
+ "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"
+ },
+ "moderated": {
+ "type": "boolean"
+ },
+ "emoji_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "emoji_name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "emoji_id",
+ "emoji_name",
+ "id",
+ "moderated",
+ "name"
+ ]
+ }
+ },
"$schema": "http://json-schema.org/draft-07/schema#"
},
"BaseAutomodRuleSchema": {
@@ -8703,6 +9433,50 @@
},
"$schema": "http://json-schema.org/draft-07/schema#"
},
+ "InviteListResponse": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/PublicInvite"
+ },
+ "definitions": {
+ "Tag": {
+ "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"
+ },
+ "moderated": {
+ "type": "boolean"
+ },
+ "emoji_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "emoji_name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "emoji_id",
+ "emoji_name",
+ "id",
+ "moderated",
+ "name"
+ ]
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+ },
"FieldErrorResponse": {
"type": "object",
"properties": {
@@ -8724,13 +9498,6 @@
],
"$schema": "http://json-schema.org/draft-07/schema#"
},
- "InviteListResponse": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/PublicInvite"
- },
- "$schema": "http://json-schema.org/draft-07/schema#"
- },
"RouteResponse": {
"type": "object",
"properties": {
@@ -12324,7 +13091,7 @@
"type": "boolean"
},
"mute_config": {
- "$ref": "#/definitions/ThreadMemberMuteConfig"
+ "$ref": "#/definitions/MuteConfig"
},
"flags": {
"$ref": "#/definitions/ThreadMemberFlags"
@@ -12683,20 +13450,6 @@
],
"$schema": "http://json-schema.org/draft-07/schema#"
},
- "ThreadMemberMuteConfig": {
- "type": "object",
- "properties": {
- "end_time": {
- "type": "string",
- "format": "date-time"
- },
- "selected_time_window": {
- "type": "integer"
- }
- },
- "additionalProperties": false,
- "$schema": "http://json-schema.org/draft-07/schema#"
- },
"ThreadMemberFlags": {
"type": "number",
"enum": [
@@ -15522,6 +16275,164 @@
],
"$schema": "http://json-schema.org/draft-07/schema#"
},
+ "PaymentSource": {
+ "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"
+ },
+ "brand": {
+ "type": "string"
+ },
+ "country": {
+ "type": "string"
+ },
+ "last_4": {
+ "type": "string"
+ },
+ "billing_address": {
+ "$ref": "#/definitions/BillingAddress"
+ },
+ "type": {
+ "$ref": "#/definitions/PaymentSourceType"
+ },
+ "payment_gateway": {
+ "$ref": "#/definitions/PaymentGateway"
+ },
+ "payment_gateway_source_id": {
+ "type": "string"
+ },
+ "default": {
+ "type": "boolean"
+ },
+ "invalid": {
+ "type": "boolean"
+ },
+ "flags": {
+ "$ref": "#/definitions/PaymentSourceFlags"
+ },
+ "deleted_at": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "expires_month": {
+ "type": "integer"
+ },
+ "expires_year": {
+ "type": "integer"
+ },
+ "email": {
+ "type": "string"
+ },
+ "bank": {
+ "type": "string"
+ },
+ "username": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "billing_address",
+ "default",
+ "deleted_at",
+ "flags",
+ "id",
+ "invalid",
+ "payment_gateway",
+ "type"
+ ],
+ "$schema": "http://json-schema.org/draft-07/schema#"
+ },
+ "BillingAddress": {
+ "type": "object",
+ "properties": {
+ "line_1": {
+ "type": "string"
+ },
+ "line_2": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "name": {
+ "type": "string"
+ },
+ "postal_code": {
+ "type": "string"
+ },
+ "city": {
+ "type": "string"
+ },
+ "state": {
+ "type": "string"
+ },
+ "country": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "city",
+ "country",
+ "line_1",
+ "name"
+ ],
+ "$schema": "http://json-schema.org/draft-07/schema#"
+ },
+ "PaymentSourceType": {
+ "type": "number",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19
+ ],
+ "$schema": "http://json-schema.org/draft-07/schema#"
+ },
+ "PaymentGateway": {
+ "type": "number",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10
+ ],
+ "$schema": "http://json-schema.org/draft-07/schema#"
+ },
+ "PaymentSourceFlags": {
+ "type": "number",
+ "enum": [
+ 1,
+ 2
+ ],
+ "$schema": "http://json-schema.org/draft-07/schema#"
+ },
"EmojiGuild": {
"type": "object",
"properties": {
@@ -16111,7 +17022,7 @@
"$ref": "#/definitions/ThreadMetadata"
},
"member": {
- "$ref": "#/definitions/ThreadMember"
+ "$ref": "#/definitions/PublicThreadMember"
},
"default_auto_archive_duration": {
"type": [
@@ -16208,6 +17119,47 @@
],
"$schema": "http://json-schema.org/draft-07/schema#"
},
+ "PublicThreadMember": {
+ "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"
+ },
+ "user_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"
+ },
+ "join_timestamp": {
+ "type": "string"
+ },
+ "flags": {
+ "$ref": "#/definitions/ThreadMemberFlags"
+ },
+ "muted": {
+ "type": "boolean"
+ },
+ "mute_config": {
+ "anyOf": [
+ {
+ "$ref": "#/definitions/MuteConfig"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "member": {
+ "$ref": "#/definitions/PublicMember"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "flags",
+ "join_timestamp"
+ ],
+ "$schema": "http://json-schema.org/draft-07/schema#"
+ },
"MessageActivity": {
"type": "object",
"properties": {
@@ -16270,6 +17222,42 @@
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
},
+ "Tag_1": {
+ "type": "object",
+ "properties": {
+ "channel_id": {
+ "type": "string"
+ },
+ "channel": {
+ "$ref": "#/definitions/Channel"
+ },
+ "name": {
+ "type": "string"
+ },
+ "moderated": {
+ "type": "boolean",
+ "default": false
+ },
+ "emoji_id": {
+ "type": "string"
+ },
+ "emoji_name": {
+ "type": "string"
+ },
+ "id": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "channel",
+ "channel_id",
+ "id",
+ "moderated",
+ "name"
+ ],
+ "$schema": "http://json-schema.org/draft-07/schema#"
+ },
"Potion": {
"type": "object",
"properties": {
@@ -16699,15 +17687,33 @@
"properties": {
"maxEmojis": {
"type": "integer",
- "default": 100
+ "default": 1000
+ },
+ "commandLimits": {
+ "$ref": "#/definitions/CommandLimits"
}
},
"additionalProperties": false,
"required": [
+ "commandLimits",
"maxEmojis"
],
"$schema": "http://json-schema.org/draft-07/schema#"
},
+ "CommandLimits": {
+ "type": "object",
+ "properties": {
+ "maxNameLength": {
+ "type": "integer",
+ "default": 32
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "maxNameLength"
+ ],
+ "$schema": "http://json-schema.org/draft-07/schema#"
+ },
"UserLimits": {
"type": "object",
"properties": {
@@ -18302,11 +19308,6 @@
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
},
- "ErrorList": {
- "type": "object",
- "additionalProperties": false,
- "$schema": "http://json-schema.org/draft-07/schema#"
- },
"PublicInvite": {
"type": "object",
"properties": {
@@ -18606,5 +19607,10 @@
3
],
"$schema": "http://json-schema.org/draft-07/schema#"
+ },
+ "ErrorList": {
+ "type": "object",
+ "additionalProperties": false,
+ "$schema": "http://json-schema.org/draft-07/schema#"
}
}
\ No newline at end of file
diff --git a/src/api/middlewares/CORS.ts b/src/api/middlewares/CORS.ts
index 6cb2b1d8c..c4aa9cc08 100644
--- a/src/api/middlewares/CORS.ts
+++ b/src/api/middlewares/CORS.ts
@@ -18,8 +18,6 @@
import { NextFunction, Request, Response } from "express";
-// TODO: config settings
-
export function CORS(req: Request, res: Response, next: NextFunction) {
res.set("Access-Control-Allow-Credentials", "true");
res.set("Access-Control-Allow-Headers", req.header("Access-Control-Request-Headers") || "*");
diff --git a/src/api/routes/applications/#application_id/commands/#command_id/index.ts b/src/api/routes/applications/#application_id/commands/#command_id/index.ts
index 6fc4e28ed..3e4df62ff 100644
--- a/src/api/routes/applications/#application_id/commands/#command_id/index.ts
+++ b/src/api/routes/applications/#application_id/commands/#command_id/index.ts
@@ -19,7 +19,7 @@
import { Request, Response, Router } from "express";
import { route } from "@spacebar/api/middlewares";
import { Application, ApplicationCommand } from "@spacebar/database";
-import { FieldErrors, Snowflake } from "@spacebar/util";
+import { Config, FieldErrors, Snowflake } from "@spacebar/util";
import { ApplicationCommandCreateSchema, ApplicationCommandSchema } from "@spacebar/schemas";
const router = Router({ mergeParams: true });
@@ -68,12 +68,11 @@ router.patch(
body.type = 1;
}
- if (body.name.trim().length < 1 || body.name.trim().length > 32) {
- // TODO: configurable?
+ if (body.name.trim().length < 1 || body.name.trim().length > Config.get().limits.application.commandLimits.maxNameLength) {
throw FieldErrors({
name: {
code: "BASE_TYPE_BAD_LENGTH",
- message: `Must be between 1 and 32 in length.`,
+ message: `Must be between 1 and ${Config.get().limits.application.commandLimits.maxNameLength} in length.`,
},
});
}
diff --git a/src/api/routes/applications/#application_id/commands/index.ts b/src/api/routes/applications/#application_id/commands/index.ts
index 4891a180f..538ea7ea8 100644
--- a/src/api/routes/applications/#application_id/commands/index.ts
+++ b/src/api/routes/applications/#application_id/commands/index.ts
@@ -21,7 +21,7 @@ import { IsNull } from "typeorm";
import { ApplicationCommandCreateSchema, ApplicationCommandSchema } from "@spacebar/schemas";
import { route } from "@spacebar/api/middlewares";
import { Application, ApplicationCommand } from "@spacebar/database";
-import { FieldErrors, Snowflake } from "@spacebar/util";
+import { Config, FieldErrors, Snowflake } from "@spacebar/util";
const router = Router({ mergeParams: true });
@@ -56,12 +56,11 @@ router.post(
body.type = 1;
}
- if (body.name.trim().length < 1 || body.name.trim().length > 32) {
- // TODO: configurable?
+ if (body.name.trim().length < 1 || body.name.trim().length > Config.get().limits.application.commandLimits.maxNameLength) {
throw FieldErrors({
name: {
code: "BASE_TYPE_BAD_LENGTH",
- message: `Must be between 1 and 32 in length.`,
+ message: `Must be between 1 and ${Config.get().limits.application.commandLimits.maxNameLength} in length.`,
},
});
}
@@ -127,12 +126,11 @@ router.put(
command.type = 1;
}
- if (command.name.trim().length < 1 || command.name.trim().length > 32) {
- // TODO: configurable?
+ if (command.name.trim().length < 1 || command.name.trim().length > Config.get().limits.application.commandLimits.maxNameLength) {
throw FieldErrors({
name: {
code: "BASE_TYPE_BAD_LENGTH",
- message: `Must be between 1 and 32 in length.`,
+ message: `Must be between 1 and ${Config.get().limits.application.commandLimits.maxNameLength} in length.`,
},
});
}
diff --git a/src/api/routes/applications/#application_id/guilds/#guild_id/commands/#command_id/index.ts b/src/api/routes/applications/#application_id/guilds/#guild_id/commands/#command_id/index.ts
index 6cbd4ae06..eea17006f 100644
--- a/src/api/routes/applications/#application_id/guilds/#guild_id/commands/#command_id/index.ts
+++ b/src/api/routes/applications/#application_id/guilds/#guild_id/commands/#command_id/index.ts
@@ -19,7 +19,7 @@
import { Request, Response, Router } from "express";
import { route } from "@spacebar/api/middlewares";
import { Application, ApplicationCommand, Guild, Member } from "@spacebar/database";
-import { FieldErrors, Snowflake } from "@spacebar/util";
+import { Config, FieldErrors, Snowflake } from "@spacebar/util";
import { ApplicationCommandCreateSchema, ApplicationCommandSchema } from "@spacebar/schemas";
const router = Router({ mergeParams: true });
@@ -87,12 +87,11 @@ router.patch(
body.type = 1;
}
- if (body.name.trim().length < 1 || body.name.trim().length > 32) {
- // TODO: configurable?
+ if (body.name.trim().length < 1 || body.name.trim().length > Config.get().limits.application.commandLimits.maxNameLength) {
throw FieldErrors({
name: {
code: "BASE_TYPE_BAD_LENGTH",
- message: `Must be between 1 and 32 in length.`,
+ message: `Must be between 1 and ${Config.get().limits.application.commandLimits.maxNameLength} in length.`,
},
});
}
diff --git a/src/api/routes/applications/#application_id/guilds/#guild_id/commands/index.ts b/src/api/routes/applications/#application_id/guilds/#guild_id/commands/index.ts
index 19444d3a8..520ca9995 100644
--- a/src/api/routes/applications/#application_id/guilds/#guild_id/commands/index.ts
+++ b/src/api/routes/applications/#application_id/guilds/#guild_id/commands/index.ts
@@ -19,7 +19,7 @@
import { Request, Response, Router } from "express";
import { route } from "@spacebar/api/middlewares";
import { Application, ApplicationCommand, Guild, Member } from "@spacebar/database";
-import { FieldErrors, Snowflake } from "@spacebar/util";
+import { Config, FieldErrors, Snowflake } from "@spacebar/util";
import { ApplicationCommandCreateSchema, ApplicationCommandSchema } from "@spacebar/schemas";
const router = Router({ mergeParams: true });
@@ -79,12 +79,11 @@ router.post(
body.type = 1;
}
- if (body.name.trim().length < 1 || body.name.trim().length > 32) {
- // TODO: configurable?
+ if (body.name.trim().length < 1 || body.name.trim().length > Config.get().limits.application.commandLimits.maxNameLength) {
throw FieldErrors({
name: {
code: "BASE_TYPE_BAD_LENGTH",
- message: `Must be between 1 and 32 in length.`,
+ message: `Must be between 1 and ${Config.get().limits.application.commandLimits.maxNameLength} in length.`,
},
});
}
@@ -165,12 +164,11 @@ router.put(
command.type = 1;
}
- if (command.name.trim().length < 1 || command.name.trim().length > 32) {
- // TODO: configurable?
+ if (command.name.trim().length < 1 || command.name.trim().length > Config.get().limits.application.commandLimits.maxNameLength) {
throw FieldErrors({
name: {
code: "BASE_TYPE_BAD_LENGTH",
- message: `Must be between 1 and 32 in length.`,
+ message: `Must be between 1 and ${Config.get().limits.application.commandLimits.maxNameLength} in length.`,
},
});
}
diff --git a/src/api/routes/beaker.ts b/src/api/routes/beaker.ts
index 88cc72c09..393c89d64 100644
--- a/src/api/routes/beaker.ts
+++ b/src/api/routes/beaker.ts
@@ -31,7 +31,6 @@ router.post(
spacebarOnly: false, // Not part of public openapi
}),
(req: Request, res: Response) => {
- // TODO:
res.sendStatus(204);
},
);
diff --git a/src/api/routes/channels/#channel_id/invites.ts b/src/api/routes/channels/#channel_id/invites.ts
index c16b9f955..d57b4f2be 100644
--- a/src/api/routes/channels/#channel_id/invites.ts
+++ b/src/api/routes/channels/#channel_id/invites.ts
@@ -21,9 +21,9 @@ import { HTTPError } from "lambert-server/HTTPError";
import { route } from "@spacebar/api/middlewares";
import { Channel, Guild, Invite, PublicInviteRelation, User } from "@spacebar/database";
import { InviteCreateEvent, emitEvent } from "@spacebar/util";
-import { InviteCreateSchema, isTextChannel } from "@spacebar/schemas";
+import { InviteCreateSchema, isTextChannel, PublicUserProjection } from "@spacebar/schemas";
import { Random } from "@spacebar/extensions";
-import { InviteListResponse } from "@spacebar/schemas/api/guilds/Invite";
+import { InviteListResponse, PublicInvite } from "@spacebar/schemas/api/guilds/Invite";
const router: Router = Router({ mergeParams: true });
@@ -35,7 +35,7 @@ router.post(
right: "CREATE_INVITES",
responses: {
201: {
- body: "Invite",
+ body: "PublicInvite",
},
404: {},
400: {
@@ -71,21 +71,20 @@ router.post(
guild_id,
channel_id: channel_id,
inviter_id: user_id,
+ inviter: await User.findOneOrFail({
+ where: { id: req.user_id },
+ select: Object.fromEntries(PublicUserProjection.map((i) => [i, true])), // TODO: clean up
+ }),
flags: body.flags ?? 0,
}).save();
- const data = invite.toJSON();
- data.inviter = await User.getPublicUser(req.user_id);
- data.guild = await Guild.findOne({ where: { id: guild_id } });
- data.channel = channel;
-
await emitEvent({
event: "INVITE_CREATE",
- data,
+ data: invite.toGatewayInviteCreateData(),
guild_id,
} satisfies InviteCreateEvent);
- res.status(201).send(data);
+ res.status(201).send(invite.toPublicJSON());
},
);
diff --git a/src/api/routes/channels/#channel_id/messages/index.ts b/src/api/routes/channels/#channel_id/messages/index.ts
index 1816aa6db..d85b05119 100644
--- a/src/api/routes/channels/#channel_id/messages/index.ts
+++ b/src/api/routes/channels/#channel_id/messages/index.ts
@@ -18,7 +18,7 @@
import { handleMessage, postHandleMessage } from "@spacebar/api/util";
import { route } from "@spacebar/api/middlewares";
-import { Attachment, Channel, Member, Message, ReadState, Relationship, User, ThreadMember, ThreadMemberFlags } from "@spacebar/database";
+import { Attachment, Channel, Member, Message, ReadState, Relationship, User, ThreadMember } from "@spacebar/database";
import {
Config,
DiscordApiErrors,
@@ -52,6 +52,7 @@ import {
Reaction,
ReadStateType,
RelationshipType,
+ ThreadMemberFlags,
} from "@spacebar/schemas";
const router: Router = Router({ mergeParams: true });
diff --git a/src/api/routes/channels/#channel_id/post-data.ts b/src/api/routes/channels/#channel_id/post-data.ts
index 202cce99b..72d582546 100644
--- a/src/api/routes/channels/#channel_id/post-data.ts
+++ b/src/api/routes/channels/#channel_id/post-data.ts
@@ -21,7 +21,7 @@ import { messageUpload } from "./messages";
import { In } from "typeorm";
import { route } from "@spacebar/api/middlewares";
import { Channel, Member, Message } from "@spacebar/database";
-import { PostDataSchema, PublicMessage } from "@spacebar/schemas";
+import { PostDataResponse, PostDataSchema, PublicMessage } from "@spacebar/schemas";
const router = Router({ mergeParams: true });
@@ -43,7 +43,9 @@ router.post(
requestBody: "PostDataSchema",
permission: "VIEW_CHANNEL",
responses: {
- 200: {},
+ 200: {
+ body: "PostDataResponse",
+ },
403: {},
},
}),
@@ -54,6 +56,7 @@ router.post(
id: In(body),
},
});
+
const [messages, members] = await Promise.all([
Message.find({
where: {
@@ -81,17 +84,18 @@ router.post(
},
}),
]);
+
await Message.fillReplies(messages);
- const objRet: { threads: Record<string, { first_message: null | PublicMessage; owner: null | Member }> } = { threads: {} };
+ const threadPostData: PostDataResponse = { threads: {} };
for (const thread of threads) {
- const owner = members.find(({ id }) => id === thread.owner_id)?.toJSON() || null;
- const first_message = messages.find(({ channel_id }) => channel_id === thread.id)?.toJSON() || null;
- objRet.threads[thread.id] = {
+ const owner = members.find(({ id }) => id === thread.owner_id)?.toPublicMember() ?? null;
+ const first_message = messages.find(({ channel_id }) => channel_id === thread.id)?.toJSON() ?? null;
+ threadPostData.threads[thread.id] = {
owner,
first_message,
};
}
- return res.json(objRet);
+ return res.json(threadPostData);
},
);
diff --git a/src/api/routes/channels/#channel_id/thread-members.ts b/src/api/routes/channels/#channel_id/thread-members.ts
index f1d2a6cf1..f6ed628ec 100644
--- a/src/api/routes/channels/#channel_id/thread-members.ts
+++ b/src/api/routes/channels/#channel_id/thread-members.ts
@@ -19,9 +19,9 @@
import { Request, Response, Router } from "express";
import { MoreThan } from "typeorm";
import { route } from "@spacebar/api/middlewares";
-import { Channel, Member, ThreadMember, ThreadMemberFlags } from "@spacebar/database";
+import { Channel, Member, ThreadMember } from "@spacebar/database";
import { emitEvent, Permissions, ThreadCreateEvent, ThreadDeleteEvent, ThreadMembersUpdateEvent } from "@spacebar/util";
-import { ChannelType, Snowflake } from "@spacebar/schemas";
+import { ChannelType, Snowflake, ThreadMemberFlags } from "@spacebar/schemas";
const router = Router({ mergeParams: true });
@@ -29,7 +29,9 @@ router.get(
"/",
route({
responses: {
- 200: {},
+ 200: {
+ body: "PublicThreadMembersResponse",
+ },
403: {},
},
permission: "VIEW_CHANNEL",
@@ -51,12 +53,14 @@ router.get(
}
return res.send(
- await ThreadMember.find({
- where: { channel: { id: channel_id }, ...(after ? { user_id: MoreThan(after) } : {}) },
- take: limit ? parseInt(limit) : 50,
- order: { member_idx: "ASC" },
- relations: { ...(with_member ? { member: true } : {}) },
- }),
+ (
+ await ThreadMember.find({
+ where: { channel: { id: channel_id }, ...(after ? { user_id: MoreThan(after) } : {}) },
+ take: limit ? parseInt(limit) : 50,
+ order: { member_idx: "ASC" },
+ relations: { ...(with_member ? { member: true } : {}) },
+ })
+ ).map((m) => m.toJSON()),
);
},
);
diff --git a/src/api/routes/guilds/#guild_id/application-command-index.ts b/src/api/routes/guilds/#guild_id/application-command-index.ts
index 758392fe8..10f404e47 100644
--- a/src/api/routes/guilds/#guild_id/application-command-index.ts
+++ b/src/api/routes/guilds/#guild_id/application-command-index.ts
@@ -64,10 +64,11 @@ router.get("/", route({}), async (req: Request, res: Response) => {
guild_id: command.guild_id,
name: command.name,
name_localizations: command.name_localizations,
- // name_localized: // TODO: make this work
+ name_localized: (command.name_localizations && req.user.settings?.locale ? command.name_localizations[req.user.settings.locale] : null) ?? command.name,
description: command.description,
description_localizations: command.description_localizations,
- // description_localized: // TODO: make this work
+ description_localized:
+ (command.description_localizations && req.user.settings?.locale ? command.description_localizations[req.user.settings.locale] : null) ?? command.description,
options: command.type === ApplicationCommandType.CHAT_INPUT ? command.options : undefined,
default_member_permissions: command.default_member_permissions,
dm_permission: command.dm_permission,
diff --git a/src/api/routes/guilds/#guild_id/bans.ts b/src/api/routes/guilds/#guild_id/bans.ts
index 821746654..1a4890b8a 100644
--- a/src/api/routes/guilds/#guild_id/bans.ts
+++ b/src/api/routes/guilds/#guild_id/bans.ts
@@ -26,6 +26,7 @@ import { BanCreateSchema, BanRegistrySchema, GuildBanResponse, GuildBansResponse
const router: Router = Router({ mergeParams: true });
/* TODO: Deleting the secrets is just a temporary go-around. Views should be implemented for both safety and better handling. */
+// Emma [it/its] @ Rory& - 2026-11-01 - what secrets?
router.get(
"/",
diff --git a/src/api/routes/guilds/#guild_id/index.ts b/src/api/routes/guilds/#guild_id/index.ts
index 9fa61a4d3..c4eb05515 100644
--- a/src/api/routes/guilds/#guild_id/index.ts
+++ b/src/api/routes/guilds/#guild_id/index.ts
@@ -109,7 +109,6 @@ router.patch(
if (body.features) {
const diff = guild.features.filter((x) => !body.features?.includes(x)).concat(body.features.filter((x) => !guild.features.includes(x)));
- // TODO move these
const MUTABLE_FEATURES = ["COMMUNITY", "INVITES_DISABLED", "DISCOVERABLE"];
for (const feature of diff) {
diff --git a/src/api/routes/guilds/#guild_id/regions.ts b/src/api/routes/guilds/#guild_id/regions.ts
index 025ea7c44..8709c9c00 100644
--- a/src/api/routes/guilds/#guild_id/regions.ts
+++ b/src/api/routes/guilds/#guild_id/regions.ts
@@ -38,7 +38,6 @@ router.get(
async (req: Request, res: Response) => {
const { guild_id } = req.params as { [key: string]: string };
const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
- //TODO we should use an enum for guild's features and not hardcoded strings
return res.json(await getVoiceRegions(req.ip!, guild.features.includes("VIP_REGIONS")));
},
);
diff --git a/src/api/routes/guilds/index.ts b/src/api/routes/guilds/index.ts
index 231ba9041..6e6bf2099 100644
--- a/src/api/routes/guilds/index.ts
+++ b/src/api/routes/guilds/index.ts
@@ -24,8 +24,6 @@ import { GuildCreateSchema } from "@spacebar/schemas";
const router: Router = Router({ mergeParams: true });
-//TODO: create default channel
-
router.post(
"/",
route({
diff --git a/src/api/routes/read-states/ack-bulk.ts b/src/api/routes/read-states/ack-bulk.ts
index 5a1cef184..07fcec962 100644
--- a/src/api/routes/read-states/ack-bulk.ts
+++ b/src/api/routes/read-states/ack-bulk.ts
@@ -37,8 +37,6 @@ router.post(
async (req: Request, res: Response) => {
const body = req.body as AckBulkSchema;
- // TODO: what is read_state_type ?
-
await Promise.all([
// for every new state
...body.read_states.map(async (x) => {
diff --git a/src/api/routes/science.ts b/src/api/routes/science.ts
index 34f342883..012a78989 100644
--- a/src/api/routes/science.ts
+++ b/src/api/routes/science.ts
@@ -30,7 +30,6 @@ router.post(
authentication: "never",
}),
(req: Request, res: Response) => {
- // TODO:
res.sendStatus(204);
},
);
diff --git a/src/api/routes/teams.ts b/src/api/routes/teams.ts
index 16fd5d3a5..1370c1eea 100644
--- a/src/api/routes/teams.ts
+++ b/src/api/routes/teams.ts
@@ -84,7 +84,7 @@ router.post(
role: TeamMemberRole.ADMIN,
}).save();
- res.json(team.toJSON() satisfies Team);
+ res.json(team.toJSON());
},
);
diff --git a/src/api/routes/users/@me/billing/payment-sources.ts b/src/api/routes/users/@me/billing/payment-sources.ts
index 3c6008cf7..ec68efd12 100644
--- a/src/api/routes/users/@me/billing/payment-sources.ts
+++ b/src/api/routes/users/@me/billing/payment-sources.ts
@@ -47,34 +47,63 @@ const example = {
default: false,
};
-router.get("/", route({}), (req: Request, res: Response) => {
- // TODO: schema
- res.json([example]).status(200);
-});
+router.get(
+ "/",
+ route({
+ responses: {
+ 200: { body: "PaymentSourceListResponse" },
+ },
+ }),
+ (req: Request, res: Response) => {
+ res.json([example]).status(200);
+ },
+);
-router.post("/", route({}), (req: Request, res: Response) => {
- // TODO: schema
- res.json([example]).status(200);
-});
+router.post(
+ "/",
+ route({
+ responses: {
+ 200: { body: "PaymentSourceListResponse" },
+ },
+ }),
+ // TODO: request schema
+ (req: Request, res: Response) => {
+ res.json([example]).status(200);
+ },
+);
-router.get("/:payment_source_id", route({}), (req: Request, res: Response) => {
- // TODO: schema
- res.json({
- ...example,
- id: req.route.payment_source_id,
- }).status(200);
-});
+router.get(
+ "/:payment_source_id",
+ route({
+ responses: {
+ 200: { body: "PaymentSource" },
+ },
+ }),
+ (req: Request, res: Response) => {
+ res.json({
+ ...example,
+ id: req.route.payment_source_id,
+ }).status(200);
+ },
+);
-router.patch("/:payment_source_id", route({}), (req: Request, res: Response) => {
- // TODO: schema
- res.json({
- ...example,
- id: req.route.payment_source_id,
- }).status(200);
-});
+router.patch(
+ "/:payment_source_id",
+ route({
+ responses: {
+ 200: { body: "PaymentSourceListResponse" },
+ },
+ }),
+ (req: Request, res: Response) => {
+ // TODO: request schema
+ res.json({
+ ...example,
+ id: req.route.payment_source_id,
+ }).status(200);
+ },
+);
router.delete("/:payment_source_id", route({}), (req: Request, res: Response) => {
- // TODO: schema
res.status(204);
});
diff --git a/src/api/routes/users/@me/delete.ts b/src/api/routes/users/@me/delete.ts
index e0887900a..ec29a5fa6 100644
--- a/src/api/routes/users/@me/delete.ts
+++ b/src/api/routes/users/@me/delete.ts
@@ -52,8 +52,6 @@ router.post(
}
}
- // TODO: decrement guild member count
-
if (correctpass) {
// Check if the user owns any guilds.
const ownedGuilds = await Guild.findOne({ where: { owner_id: req.user_id } });
diff --git a/src/api/routes/users/@me/guilds/#guild_id/settings.ts b/src/api/routes/users/@me/guilds/#guild_id/settings.ts
index eb3694b59..fb2f794ed 100644
--- a/src/api/routes/users/@me/guilds/#guild_id/settings.ts
+++ b/src/api/routes/users/@me/guilds/#guild_id/settings.ts
@@ -21,6 +21,8 @@ import { route } from "@spacebar/api/middlewares";
import { Channel, Member } from "@spacebar/database";
import { OrmUtils } from "@spacebar/util";
import { UserGuildSettingsSchema } from "@spacebar/schemas";
+import { In } from "typeorm";
+import { HTTPError } from "lambert-server";
const router = Router({ mergeParams: true });
@@ -60,10 +62,8 @@ router.patch(
const body = req.body as UserGuildSettingsSchema;
if (body.channel_overrides) {
- // TODO: rewrite to a single query?
- for (const channel in body.channel_overrides) {
- await Channel.findOneOrFail({ where: { id: channel } });
- }
+ const channels = await Channel.find({ where: { id: In(Object.keys(body.channel_overrides)), guild_id: req.params.guild_id as string } });
+ if (channels.length != Object.keys(body.channel_overrides).length) throw new HTTPError("Could not find one or more channels.", 404);
}
const user = await Member.findOneOrFail({
diff --git a/src/api/routes/users/@me/index.ts b/src/api/routes/users/@me/index.ts
index 341dbf1f3..59565480e 100644
--- a/src/api/routes/users/@me/index.ts
+++ b/src/api/routes/users/@me/index.ts
@@ -153,7 +153,6 @@ router.patch(
}
if (body.discriminator) {
- // TODO: HACK - maybe make this optional?
if (!/^\d{4}$/.test(body.discriminator)) {
throw FieldErrors({
discriminator: {
diff --git a/src/api/routes/users/@me/mfa/totp/enable.ts b/src/api/routes/users/@me/mfa/totp/enable.ts
index a55a9ff65..660778c8e 100644
--- a/src/api/routes/users/@me/mfa/totp/enable.ts
+++ b/src/api/routes/users/@me/mfa/totp/enable.ts
@@ -51,12 +51,11 @@ router.post(
select: { id: true, data: true, email: true },
});
- // TODO: Are guests allowed to enable 2fa?
if (user.data.hash) {
if (!(await bcrypt.compare(body.password, user.data.hash))) {
throw new HTTPError(req.t("auth:login.INVALID_PASSWORD"));
}
- }
+ } else throw new HTTPError("Guests cannot enable 2FA, please set a password first!", 403);
if (!body.secret) throw new HTTPError(req.t("auth:login.INVALID_TOTP_SECRET"), 60005);
diff --git a/src/api/util/handlers/Message.ts b/src/api/util/handlers/Message.ts
index 2940b3064..3be73067e 100644
--- a/src/api/util/handlers/Message.ts
+++ b/src/api/util/handlers/Message.ts
@@ -558,7 +558,6 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
return message;
}
-// TODO: cache link result in db
export async function postHandleMessage(message: Message) {
message.clean_data();
@@ -773,25 +772,21 @@ async function handleMessageMentionsAsync(message: Message) {
mention_roles: true,
},
});
+
if (referencedMessage && referencedMessage.author_id !== message.author_id) {
- message.mentions.push(
- // @ts-expect-error it does not like the .toPublicUser() lol
- (await User.findOne({ where: { id: referencedMessage.author_id } }))!.toPublicUser(),
- );
+ const user = await User.findOne({ where: { id: referencedMessage.author_id } });
+ if (user) message.mentions.push(user);
}
if (message.embeds[0]?.type === EmbedType.poll_result) {
- message.mentions.push(
- // @ts-expect-error it does not like the .toPublicUser() lol
- (await User.findOne({ where: { id: message.author_id } }))!.toPublicUser(),
- );
+ const user = await User.findOne({ where: { id: message.author_id } });
+ if (user) message.mentions.push(user);
}
if (message.message_reference.type === MessageReferenceType.FORWARD) {
message.type = MessageType.DEFAULT;
if (message.referenced_message) {
- // TODO: mention_roles and mentions arrays - not needed it seems, but discord still returns that
message.message_snapshots = [message.referenced_message.toSnapshot()];
}
}
diff --git a/src/database/entities/BaseClass.ts b/src/database/entities/BaseClass.ts
index 730a769f4..6d4bfdaf8 100644
--- a/src/database/entities/BaseClass.ts
+++ b/src/database/entities/BaseClass.ts
@@ -76,9 +76,7 @@ export class BaseClassWithoutId extends BaseEntity {
return this;
}
- // TODO: fix eslint
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- toJSON(): any {
+ toJSON(): unknown {
this.clean_data();
return Object.fromEntries(
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
diff --git a/src/database/entities/Guild.ts b/src/database/entities/Guild.ts
index d325a1caf..3526c1cfd 100644
--- a/src/database/entities/Guild.ts
+++ b/src/database/entities/Guild.ts
@@ -21,6 +21,8 @@ import { arrayRemove } from "@spacebar/extensions";
import { Config, handleFile, Snowflake } from "@spacebar/util";
import {
DiscoverableGuild,
+ DiscoveryCategory,
+ EmojiResponse,
GuildNsfwLevel,
GuildPremiumTier,
GuildProfileResponse,
@@ -28,6 +30,7 @@ import {
GuildVisibilityLevel,
GuildWelcomeScreen,
IntegrationGuild,
+ StickerResponse,
} from "@spacebar/schemas";
import { Ban } from "./Ban";
import { BaseClass } from "./BaseClass";
@@ -342,9 +345,9 @@ export class Guild extends BaseClass {
},
},
}),*/
- emojis: this.emojis?.map((e) => e.toJSON()) ?? undefined,
+ emojis: (this.emojis?.map((e) => e.toJSON()) as EmojiResponse[]) ?? undefined,
emoji_count: this.emojis ? this.emojis.length : undefined,
- stickers: this.stickers?.map((s) => s.toJSON()) ?? undefined,
+ stickers: (this.stickers?.map((s) => s.toJSON()) as StickerResponse[]) ?? undefined,
sticker_count: this.stickers ? this.stickers.length : undefined,
auto_removed: false,
primary_category_id: this.primary_category_id!,
@@ -353,13 +356,13 @@ export class Guild extends BaseClass {
reasons_to_join: [],
created_at: new Date(Snowflake.deconstruct(this.id).timestamp).toISOString(), // TODO: make column
primary_category: this.primary_category_id
- ? (
+ ? ((
await Categories.findOneOrFail({
where: {
id: this.primary_category_id!,
},
})
- ).toJSON()
+ ).toJSON() as DiscoveryCategory)
: undefined,
};
}
diff --git a/src/database/entities/Invite.ts b/src/database/entities/Invite.ts
index 4c338f4e2..6de0d8ff8 100644
--- a/src/database/entities/Invite.ts
+++ b/src/database/entities/Invite.ts
@@ -22,7 +22,7 @@ import { Channel } from "./Channel";
import { Guild } from "./Guild";
import { Member } from "./Member";
import { User } from "./User";
-import { InviteType, PublicInvite } from "@spacebar/schemas/api/guilds/Invite";
+import { InviteCreateEventData, InviteType, PublicInvite } from "@spacebar/schemas/api/guilds/Invite";
export const PublicInviteRelation = ["inviter", "guild", "channel"];
@@ -105,6 +105,7 @@ export class Invite extends BaseClassWithoutId {
if (this.max_uses !== 0 && this.uses >= this.max_uses) return true;
return false;
}
+
toPublicJSON(): PublicInvite {
return {
code: this.code,
@@ -128,6 +129,26 @@ export class Invite extends BaseClassWithoutId {
};
}
+ toGatewayInviteCreateData(): InviteCreateEventData {
+ return {
+ code: this.code,
+ type: InviteType.GUILD, // TODO: support other invite types
+ channel_id: this.channel_id ?? this.channel.id,
+ guild_id: this.guild_id ?? this.channel.guild_id,
+ inviter: this.inviter.toPartialUser(),
+ expires_at: this.expires_at?.toString() ?? null,
+ target_type: undefined, // TODO
+ target_user: undefined, // TODO
+ created_at: this.created_at.toISOString(),
+ max_age: this.max_age,
+ max_uses: this.max_uses,
+ temporary: this.temporary,
+ uses: this.uses,
+ role_ids: [], // TODO
+ target_application: undefined, // TODO
+ } satisfies InviteCreateEventData;
+ }
+
static async joinGuild(user_id: string, code: string) {
const invite = await Invite.findOneOrFail({ where: { code } });
if (invite.isExpired()) {
diff --git a/src/database/entities/Message.ts b/src/database/entities/Message.ts
index 629e68741..34920e713 100644
--- a/src/database/entities/Message.ts
+++ b/src/database/entities/Message.ts
@@ -390,7 +390,7 @@ export class Message extends BaseClass {
embeds: this.embeds,
flags: this.flags,
mention_roles: this.mention_roles?.map((x) => x.id),
- mentions: this.mentions.map((x) => x.toPublicUser() as unknown as PartialUser), // TODO: write a proper method for this
+ mentions: this.mentions.map((x) => x.toPartialUser()),
timestamp: this.timestamp,
type: this.type,
},
diff --git a/src/database/entities/Tag.ts b/src/database/entities/Tag.ts
index 611122a98..08113e969 100644
--- a/src/database/entities/Tag.ts
+++ b/src/database/entities/Tag.ts
@@ -17,6 +17,7 @@
*/
import { Column, Entity, JoinColumn, ManyToOne } from "typeorm";
+import { Tag as Tag_ } from "@spacebar/schemas";
import { BaseClass } from "./BaseClass";
import { Channel } from "./Channel";
@@ -45,13 +46,13 @@ export class Tag extends BaseClass {
@Column({ nullable: true })
emoji_name?: string;
- toJSON() {
+ toJSON(): Tag_ {
return {
name: this.name,
id: this.id,
moderated: this.moderated,
- emoji_id: this.emoji_id,
- emoji_name: this.emoji_name,
+ emoji_id: this.emoji_id ?? null,
+ emoji_name: this.emoji_name ?? null,
};
}
}
diff --git a/src/database/entities/ThreadMember.ts b/src/database/entities/ThreadMember.ts
index de7e881c7..ded086af7 100644
--- a/src/database/entities/ThreadMember.ts
+++ b/src/database/entities/ThreadMember.ts
@@ -18,27 +18,13 @@
import { Column, Entity, Index, JoinColumn, ManyToOne, PrimaryGeneratedColumn, RelationId } from "typeorm";
import { ThreadMembersUpdateEvent } from "../../util/interfaces";
+import { HTTPError } from "lambert-server/HTTPError";
import { emitEvent } from "@spacebar/util/util";
+import { MuteConfig, PublicThreadMember, ThreadMemberFlags } from "@spacebar/schemas";
import { BaseClassWithoutId } from "./BaseClass";
import { Channel } from "./Channel";
-import { HTTPError } from "lambert-server/HTTPError";
import { Member } from "./Member";
-// TODO: move
-interface ThreadMemberMuteConfig {
- end_time?: Date;
- selected_time_window?: number;
-}
-
-// TODO: move
-export enum ThreadMemberFlags {
- NONE = 0,
- HAS_INTERACTED = 1 << 0,
- ALL_MESSAGES = 1 << 1,
- ONLY_MENTIONS = 1 << 2,
- NO_MESSAGES = 1 << 3,
-}
-
@Entity("thread_members")
@Index(["id", "member_idx"], { unique: true })
export class ThreadMember extends BaseClassWithoutId {
@@ -72,7 +58,7 @@ export class ThreadMember extends BaseClassWithoutId {
muted: boolean;
@Column({ nullable: true, type: "jsonb" })
- mute_config?: ThreadMemberMuteConfig;
+ mute_config?: MuteConfig;
@Column()
flags: ThreadMemberFlags;
@@ -93,20 +79,18 @@ export class ThreadMember extends BaseClassWithoutId {
}))
)
throw new HTTPError("You are not member of this thread", 403);
- // // use promise all to execute all promises at the same time -> save time
- // TODO: check for bugs
+
if (channel.member_count) channel.member_count--;
return Promise.all([
ThreadMember.delete({
id: thread_id,
member_idx: member_id,
}),
- // //Guild.decrement({ id: guild_id }, "member_count", -1),
emitEvent({
event: "THREAD_MEMBERS_UPDATE",
data: {
- guild_id: channel.guild_id!, // TODO: is this the right fix?
+ guild_id: channel.guild_id!,
id: channel.id,
member_count: channel.member_count ?? 0,
removed_member_ids: [member_id],
@@ -116,6 +100,18 @@ export class ThreadMember extends BaseClassWithoutId {
]);
}
+ toJSON(): PublicThreadMember {
+ return {
+ id: this.id,
+ flags: this.flags,
+ join_timestamp: this.join_timestamp.toISOString(),
+ member: this.member.toPublicMember(),
+ mute_config: this.mute_config,
+ muted: this.muted,
+ user_id: this.member.id,
+ } satisfies PublicThreadMember;
+ }
+
// static async addRole(user_id: string, guild_id: string, role_id: string) {
// const [member, role] = await Promise.all([
// // @ts-ignore
diff --git a/src/schemas/api/channels/Channel.ts b/src/schemas/api/channels/Channel.ts
index 33514b82c..90bcdad60 100644
--- a/src/schemas/api/channels/Channel.ts
+++ b/src/schemas/api/channels/Channel.ts
@@ -17,10 +17,10 @@
*/
// TODO: remove entity imports
-import { Channel, Recipient, Tag, ThreadMember } from "@spacebar/database";
+import { Channel, Recipient } from "@spacebar/database";
import { HTTPError } from "lambert-server/HTTPError";
import { Snowflake } from "../../Identifiers";
-import { PartialUser, PublicMember } from "../users";
+import { MuteConfig, PartialUser, PublicMember } from "../users";
export enum ChannelType {
GUILD_TEXT = 0, // a text channel within a guild
@@ -127,7 +127,7 @@ export interface PublicChannel {
member_count?: number;
member_ids_preview?: Snowflake[];
thread_metadata?: ThreadMetadata;
- member?: ThreadMember;
+ member?: PublicThreadMember;
default_auto_archive_duration?: number | null;
default_thread_rate_limit_per_user?: number;
permissions?: string;
@@ -150,3 +150,30 @@ export interface PublicChannel {
is_linkable?: boolean;
is_viewable_and_writeable_by_all_members?: boolean;
}
+
+export type PublicThreadMembersResponse = PublicThreadMember[];
+export interface PublicThreadMember {
+ id?: Snowflake;
+ user_id?: Snowflake;
+ join_timestamp: string;
+ flags: ThreadMemberFlags;
+ muted?: boolean;
+ mute_config?: MuteConfig | null;
+ member?: PublicMember;
+}
+
+export enum ThreadMemberFlags {
+ NONE = 0,
+ HAS_INTERACTED = 1 << 0,
+ ALL_MESSAGES = 1 << 1,
+ ONLY_MENTIONS = 1 << 2,
+ NO_MESSAGES = 1 << 3,
+}
+
+export interface Tag {
+ id: Snowflake;
+ name: string;
+ moderated: boolean;
+ emoji_id: Snowflake | null;
+ emoji_name: string | null;
+}
diff --git a/src/schemas/api/developers/Application.ts b/src/schemas/api/developers/Application.ts
index 10e49a6bd..b2ccd1e46 100644
--- a/src/schemas/api/developers/Application.ts
+++ b/src/schemas/api/developers/Application.ts
@@ -1,6 +1,6 @@
/*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
- Copyright (C) 2023 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
@@ -16,6 +16,8 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+import { ApplicationSku, PartialUser, Snowflake, Team } from "@spacebar/schemas";
+
export interface ApplicationCommand {
id: string;
application_id: string;
@@ -60,3 +62,285 @@ export interface ApplicationCommandInteractionDataOption {
value?: unknown;
options?: ApplicationCommandInteractionDataOption[];
}
+
+export interface Application {
+ id: Snowflake;
+ name: string;
+ description: string;
+ icon: string | null;
+ cover_image?: string;
+ splash?: string;
+ type: ApplicationType | null;
+ flags: number; // ApplicationFlags
+ flags_new: string; // ApplicationFlags
+ primary_sku_id?: Snowflake;
+ verify_key: string;
+ guild_id?: Snowflake;
+ eula_id?: Snowflake;
+ slug?: string;
+ aliases?: string[];
+ executables?: ApplicationExecutable[];
+ third_party_skus?: ApplicationSku[];
+ hook: boolean;
+ overlay?: boolean;
+ overlay_methods?: number; // OverlayMethodFlags
+ overlay_warn?: boolean;
+ overlay_compatibility_hook?: boolean;
+ bot?: PartialUser;
+ owner: PartialUser;
+ team?: Team | null;
+ developers?: Company[];
+ publishers?: Company[];
+ rpc_origins?: string[];
+ redirect_uris: string[];
+ deeplink_uri?: string;
+ integration_public: boolean;
+ integration_require_code_grant: boolean;
+ bot_public?: boolean;
+ bot_require_code_grant?: boolean;
+ bot_disabled?: boolean;
+ bot_quarantined?: boolean;
+ bot_approximate_guild_count?: number;
+ approximate_guild_count?: number;
+ approximate_user_install_count: number;
+ approximate_user_authorization_count: number;
+ internal_guild_restriction: InternalGuildRestriction;
+ terms_of_service_url?: string;
+ privacy_policy_url?: string;
+ role_connections_verification_url: string | null;
+ interactions_endpoint_url: string;
+ interactions_version: number;
+ interactions_event_types: string[];
+ event_webhooks_status?: EventWebhooksStatus;
+ event_webhooks_url?: string;
+ event_webhooks_types?: string[];
+ explicit_content_filter: number;
+ tags?: string[];
+ install_params?: ApplicationInstallParams;
+ custom_install_url?: string;
+ integration_types_config?: Record<number, ApplicationIntegrationTypeConfiguration | null>;
+ connection_entrypoint_url?: string;
+ is_verified: boolean;
+ verification_state: ApplicationVerificationState;
+ store_application_state: StoreApplicationState;
+ rpc_application_state: RpcApplicationState;
+ creator_monetization_state: number; // unknown enum
+ is_discoverable: boolean;
+ discoverability_state: ApplicationDiscoverabilityState;
+ discovery_eligibility_flags: number; // ApplicationDiscoveryEligibilityFlags
+ is_monetized: boolean;
+ storefront_available: boolean;
+ monetization_state: ApplicationMonetizationState;
+ monetization_eligibility_flags?: number; // ApplicationMonetizationEligibilityFlags
+ max_participants?: number;
+ embedded_activity_config?: EmbeddedActivityConfig;
+ approved_consoles: ApprovableConsoleType[];
+ pricing_localization_strategy: string;
+}
+
+export enum ApplicationType {
+ DEPRECATED_GAME = 1,
+ TICKETED_EVENTS = 3,
+ CREATOR_MONETIZATION = 4,
+ GAME = 5,
+}
+const OverlayMethodFlags = {
+ OUT_OF_PROCESS: 1n << 0n,
+} as const;
+
+export enum InternalGuildRestriction {
+ JOIN_ALL = 1,
+ JOIN_EXTERNAL_ONLY = 2,
+ JOIN_INTERNAL_ONLY = 3,
+}
+export enum EventWebhooksStatus {
+ DISABLED = 1,
+ ENABLED = 2,
+}
+
+export enum ApplicationVerificationState {
+ INELIGIBLE = 1,
+ UNSUBMITTED = 2,
+ SUBMITTED = 3,
+ APPROVED_MANUALLY = 4,
+ BLOCKED = 5,
+ APPROVED_AUTOMATICALLY = 6,
+}
+
+export enum StoreApplicationState {
+ NONE = 1,
+ PAID = 2,
+ SUBMITTED = 3,
+ APPROVED = 4,
+ REJECTED = 5,
+}
+
+export enum RpcApplicationState {
+ DISABLED = 0,
+ UNSUBMITTED = 1,
+ SUBMITTED = 2,
+ APPROVED = 3,
+ REJECTED = 4,
+}
+
+export enum ApplicationDiscoverabilityState {
+ INELIGIBLE = 1,
+ NOT_DISCOVERABLE = 2,
+ DISCOVERABLE = 3,
+ FEATUREABLE = 4,
+ BLOCKED = 5,
+}
+
+const ApplicationDiscoveryEligibilityFlags = {
+ VERIFIED: 1n << 0n,
+ TAG: 1n << 1n,
+ DESCRIPTION: 1n << 2n,
+ TERMS_OF_SERVICE: 1n << 3n,
+ PRIVACY_POLICY: 1n << 4n,
+ INSTALL_PARAMS: 1n << 5n,
+ SAFE_NAME: 1n << 6n,
+ SAFE_DESCRIPTION: 1n << 7n,
+ APPROVED_COMMANDS: 1n << 8n,
+ SUPPORT_GUILD: 1n << 9n,
+ SAFE_COMMANDS: 1n << 10n,
+ MFA: 1n << 11n,
+ SAFE_DIRECTORY_OVERVIEW: 1n << 12n,
+ SUPPORTED_LOCALES: 1n << 13n,
+ SAFE_SHORT_DESCRIPTION: 1n << 14n,
+ SAFE_ROLE_CONNECTIONS: 1n << 15n,
+} as const;
+
+export enum ApplicationMonetizationState {
+ NONE = 1,
+ ENABLED = 2,
+ BLOCKED = 3,
+}
+
+const ApplicationMonetizationEligibilityFlags = {
+ VERIFIED: 1n << 0n,
+ HAS_TEAM: 1n << 1n,
+ APPROVED_COMMANDS: 1n << 2n,
+ TERMS_OF_SERVICE: 1n << 3n,
+ PRIVACY_POLICY: 1n << 4n,
+ SAFE_NAME: 1n << 5n,
+ SAFE_DESCRIPTION: 1n << 6n,
+ SAFE_ROLE_CONNECTIONS: 1n << 7n,
+ USER_IS_TEAM_OWNER: 1n << 8n,
+ NOT_QUARANTINED: 1n << 9n,
+ USER_LOCALE_SUPPORTED: 1n << 10n,
+ USER_AGE_SUPPORTED: 1n << 11n,
+ USER_DATE_OF_BIRTH_DEFINED: 1n << 12n,
+ USER_MFA_ENABLED: 1n << 13n,
+ USER_EMAIL_VERIFIED: 1n << 14n,
+ TEAM_MEMBERS_EMAIL_VERIFIED: 1n << 15n,
+ TEAM_MEMBERS_MFA_ENABLED: 1n << 16n,
+ NO_BLOCKING_ISSUES: 1n << 17n,
+ VALID_PAYOUT_STATUS: 1n << 18n,
+} as const;
+
+export enum ApprovableConsoleType {
+ XBOX = 1,
+ PLAYSTATION_5 = 2,
+ PLAYSTATION_4 = 3,
+}
+
+const ApplicationFlags = {
+ EMBEDDED_RELEASED: 1n << 1n,
+ MANAGED_EMOJI: 1n << 2n,
+ EMBEDDED_IAP: 1n << 3n,
+ GROUP_DM_CREATE: 1n << 4n,
+ RPC_PRIVATE_BETA: 1n << 5n,
+ AUTO_MODERATION_RULE_CREATE_BADGE: 1n << 6n,
+ GAME_PROFILE_DISABLED: 1n << 7n,
+ PUBLIC_OAUTH2_CLIENT: 1n << 8n,
+ CONTEXTLESS_ACTIVITY: 1n << 9n,
+ SOCIAL_LAYER_INTEGRATION_LIMITED: 1n << 10n,
+ CLOUD_GAMING_DEMO: 1n << 11n,
+ GATEWAY_PRESENCE: 1n << 12n,
+ GATEWAY_PRESENCE_LIMITED: 1n << 13n,
+ GATEWAY_GUILD_MEMBERS: 1n << 14n,
+ GATEWAY_GUILD_MEMBERS_LIMITED: 1n << 15n,
+ VERIFICATION_PENDING_GUILD_LIMIT: 1n << 16n,
+ EMBEDDED: 1n << 17n,
+ GATEWAY_MESSAGE_CONTENT: 1n << 18n,
+ GATEWAY_MESSAGE_CONTENT_LIMITED: 1n << 19n,
+ EMBEDDED_FIRST_PARTY: 1n << 20n,
+ APPLICATION_COMMAND_MIGRATED: 1n << 21n,
+ APPLICATION_COMMAND_BADGE: 1n << 23n,
+ ACTIVE: 1n << 24n,
+ ACTIVE_GRACE_PERIOD: 1n << 25n,
+ IFRAME_MODAL: 1n << 26n,
+ SOCIAL_LAYER_INTEGRATION: 1n << 27n,
+ PROMOTED: 1n << 29n,
+ PARTNER: 1n << 30n,
+ PARENT: 1n << 33n,
+ DISABLE_RELATIONSHIP_ACCESS: 1n << 34n,
+ STOREFRONT_ELIGIBLE: 1n << 35n,
+} as const;
+
+export interface ApplicationExecutable {
+ os: string;
+ name: string;
+ is_launcher: boolean;
+}
+
+export interface Company {
+ id: Snowflake;
+ name: string;
+}
+
+export interface ApplicationInstallParams {
+ scopes: string[];
+ permissions: string;
+}
+
+export interface ApplicationIntegrationTypeConfiguration {
+ oauth2_install_params?: ApplicationInstallParams;
+}
+
+export interface EmbeddedActivityConfig {
+ application_id?: Snowflake;
+ activity_preview_video_asset_id: Snowflake | null;
+ supported_platforms: string[];
+ default_orientation_lock_state: EmbeddedActivityOrientationLockStateType;
+ tablet_default_orientation_lock_state: EmbeddedActivityOrientationLockStateType;
+ requires_age_gate: boolean;
+ legacy_responsive_aspect_ratio: boolean;
+ premium_tier_requirement: number | null;
+ free_period_starts_at: string | null;
+ free_period_ends_at: string | null;
+ client_platform_config: Record<string, EmbeddedActivityPlatformConfig>;
+ shelf_rank: number;
+ has_csp_exception: boolean;
+ displays_advertisements: boolean;
+ supported_locales: string[];
+ blocked_locales: string[];
+}
+
+export enum EmbeddedActivityOrientationLockStateType {
+ UNLOCKED = 1,
+ PORTRAIT = 2,
+ LANDSCAPE = 3,
+}
+
+export interface EmbeddedActivityPlatformConfig {
+ label_type: EmbeddedActivityPlatformConfigLabelType;
+ label_until?: string | null;
+ release_phase: EmbeddedActivityReleasePhase;
+ omit_badge_from_surfaces: string[];
+}
+
+export enum EmbeddedActivityPlatformConfigLabelType {
+ NONE = 0,
+ NEW = 1,
+ UPDATED = 2,
+}
+
+export enum EmbeddedActivityReleasePhase {
+ IN_DEVELOPMENT = "in_development",
+ ACTIVITIES_TEAM = "activities_team",
+ EMPLOYEE_RELEASE = "employee_release",
+ SOFT_LAUNCH = "soft_launch",
+ SOFT_LAUNCH_MULTI_GEO = "soft_launch_multi_geo",
+ GLOBAL_LAUNCH = "global_launch",
+}
diff --git a/src/schemas/api/guilds/Invite.ts b/src/schemas/api/guilds/Invite.ts
index efa000f82..51b2e7999 100644
--- a/src/schemas/api/guilds/Invite.ts
+++ b/src/schemas/api/guilds/Invite.ts
@@ -19,7 +19,7 @@
import { Snowflake } from "../../Identifiers";
import { PartialUser } from "../users";
import { GuildNsfwLevel, GuildPremiumTier, GuildVerificationLevel } from "./GuildSchema";
-import { GuildProfileResponse, PublicChannel, RoleColors } from "@spacebar/schemas";
+import { Application, GuildProfileResponse, PublicChannel, RoleColors } from "@spacebar/schemas";
export type InviteListResponse = PublicInvite[];
@@ -100,3 +100,21 @@ export interface InviteRole {
icon?: string | null;
unicode_emoji?: string | null;
}
+
+export interface InviteCreateEventData {
+ code: string;
+ type: InviteType;
+ channel_id: Snowflake;
+ guild_id: Snowflake;
+ inviter?: PartialUser;
+ target_type?: number;
+ target_user?: PartialUser;
+ target_application?: Application; // PartialApplication
+ role_ids?: Snowflake[];
+ expires_at: string | null;
+ created_at: string;
+ uses: number;
+ max_uses: number;
+ max_age: number;
+ temporary: boolean;
+}
diff --git a/src/schemas/api/users/PaymentSource.ts b/src/schemas/api/users/PaymentSource.ts
new file mode 100644
index 000000000..1f7d5f15f
--- /dev/null
+++ b/src/schemas/api/users/PaymentSource.ts
@@ -0,0 +1,89 @@
+/*
+ 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 "@spacebar/schemas";
+
+export type PaymentSourceListResponse = PaymentSource[];
+export interface PaymentSource {
+ id: Snowflake;
+ brand?: string;
+ country?: string;
+ last_4?: string;
+ billing_address: BillingAddress;
+ type: PaymentSourceType;
+ payment_gateway: PaymentGateway;
+ payment_gateway_source_id?: string;
+ default: boolean;
+ invalid: boolean;
+ flags: PaymentSourceFlags;
+ deleted_at: string | null;
+ expires_month?: number;
+ expires_year?: number;
+ email?: string;
+ bank?: string;
+ username?: string;
+}
+
+export interface BillingAddress {
+ line_1: string;
+ line_2?: string | null;
+ name: string;
+ postal_code?: string;
+ city: string;
+ state?: string;
+ country: string;
+}
+export enum PaymentSourceType {
+ CARD = 1,
+ PAYPAL = 2,
+ GIROPAY = 3,
+ SOFORT = 4,
+ PRZELEWY24 = 5,
+ SEPA_DEBIT = 6,
+ PAYSAFE_CARD = 7,
+ GCASH = 8,
+ GRABPAY_MY = 9,
+ MOMO_WALLET = 10,
+ VENMO = 11,
+ GOPAY_WALLET = 12,
+ KAKAOPAY = 13,
+ BANCONTACT = 14,
+ EPS = 15,
+ IDEAL = 16,
+ CASH_APP = 17,
+ APPLE = 18,
+ TDS_WALLET = 19,
+}
+
+export enum PaymentGateway {
+ STRIPE = 1,
+ BRAINTREE = 2,
+ APPLE = 3,
+ GOOGLE = 4,
+ ADYEN = 5,
+ APPLE_PARTNER = 6,
+ AMAZON = 7,
+ VIRTUAL_CURRENCY = 8,
+ APPLE_ADVANCED_COMMERCE = 9,
+ TDS = 10,
+}
+
+export enum PaymentSourceFlags {
+ NEW = 1 << 0,
+ SUCCESSFUL_PAYMENT = 1 << 1,
+}
diff --git a/src/schemas/api/users/index.ts b/src/schemas/api/users/index.ts
index f49cfc54e..9051ea354 100644
--- a/src/schemas/api/users/index.ts
+++ b/src/schemas/api/users/index.ts
@@ -19,6 +19,7 @@
export * from "./ConnectedAccount";
export * from "./InstanceUserDeleteSchema";
export * from "./Member";
+export * from "./PaymentSource";
export * from "./RelationshipSchemas";
export * from "./SessionsSchemas";
export * from "./Status";
diff --git a/src/schemas/uncategorised/PostDataSchema.ts b/src/schemas/uncategorised/PostDataSchema.ts
index b380610d3..c8abd02f1 100644
--- a/src/schemas/uncategorised/PostDataSchema.ts
+++ b/src/schemas/uncategorised/PostDataSchema.ts
@@ -1,6 +1,6 @@
/*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
- Copyright (C) 2023 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
@@ -16,6 +16,16 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+import { PublicMember, PublicMessage, Snowflake } from "@spacebar/schemas";
+
export interface PostDataSchema {
thread_ids: string[];
}
+
+export interface PostDataResponse {
+ threads: Record<Snowflake, PostData>;
+}
+export interface PostData {
+ owner: PublicMember | null;
+ first_message: PublicMessage | null;
+}
diff --git a/src/util/config/types/subconfigurations/limits/ApplicationLimits.ts b/src/util/config/types/subconfigurations/limits/ApplicationLimits.ts
index 47e09386f..52d492607 100644
--- a/src/util/config/types/subconfigurations/limits/ApplicationLimits.ts
+++ b/src/util/config/types/subconfigurations/limits/ApplicationLimits.ts
@@ -17,5 +17,10 @@
*/
export class ApplicationLimits {
- maxEmojis: number = 100;
+ maxEmojis: number = 1000;
+ commandLimits: CommandLimits = new CommandLimits();
+}
+
+export class CommandLimits {
+ maxNameLength: number = 32;
}
diff --git a/src/util/interfaces/Event.ts b/src/util/interfaces/Event.ts
index 66a25e6db..fc24dc729 100644
--- a/src/util/interfaces/Event.ts
+++ b/src/util/interfaces/Event.ts
@@ -30,12 +30,14 @@ import {
PublicChannel,
PublicMember,
PublicMessage,
+ PublicThreadMember,
PublicUser,
PublicVoiceState,
RelationshipSchema,
RelationshipType,
UserPrivate,
} from "@spacebar/schemas";
+import { InviteCreateEventData } from "@spacebar/schemas/api/guilds/Invite";
export interface Event {
guild_id?: string;
@@ -320,10 +322,7 @@ export interface GuildRoleDeleteEvent extends Event {
export interface InviteCreateEvent extends Event {
event: "INVITE_CREATE";
- data: Omit<Invite, "guild" | "channel"> & {
- channel_id: string;
- guild_id?: string;
- };
+ data: InviteCreateEventData;
}
export interface InviteDeleteEvent extends Event {
@@ -665,7 +664,7 @@ export interface ThreadMembersUpdateEvent extends Event {
id: string;
guild_id: string;
member_count: number;
- added_members?: (ThreadMember & { user_id: string })[];
+ added_members?: PublicThreadMember[];
removed_member_ids?: string[];
};
}
diff --git a/src/util/util/ipc/writer/UnixSocketWriter.ts b/src/util/util/ipc/writer/UnixSocketWriter.ts
index ae143f7e1..99a2dc5a8 100644
--- a/src/util/util/ipc/writer/UnixSocketWriter.ts
+++ b/src/util/util/ipc/writer/UnixSocketWriter.ts
@@ -108,7 +108,7 @@ export class UnixSocketWriter extends BaseEventWriter {
delete this.clients[fullPath];
}
- console.error("[UnixSocketWriter] Unix socket client error on", fullPath, ":", err);
+ console.error("[UnixSocketWriter] Unix socket client error on", fullPath, ":", summariseError(err));
rej(err);
});
@@ -127,7 +127,7 @@ export class UnixSocketWriter extends BaseEventWriter {
let tries = 0;
let lastError: Error | undefined = undefined;
- while (tries++ < 10) {
+ while (tries++ < 9) {
if (tries > 1) {
const delay = Math.pow(tries, 3.5);
console.warn("[UnixSocketWriter] Attemption connects to", fullPath, "have been failing... Trying again in", delay, "millis...");
@@ -143,7 +143,7 @@ export class UnixSocketWriter extends BaseEventWriter {
}
if (tries >= 10 && lastError !== undefined) {
- console.error("[UnixSocketWriter] Exhausted all", tries, "attempts at connecting to", fullPath, "- Error:", lastError);
+ console.error("[UnixSocketWriter] Exhausted all", tries, "attempts at connecting to", fullPath, "-", summariseError(lastError));
if ("code" in lastError && lastError.code == "ECONNREFUSED") {
console.error("[UnixSocketWriter] Got ECONNREFUSED for socket", fullPath, " - assuming it is orphaned...");
fs.unlinkSync(fullPath);
@@ -286,3 +286,13 @@ function getPidCmdline(pid: number): string | null {
return null;
}
}
+
+function summariseError(err: Error) {
+ // we dont care about these:
+ if ("syscall" in err && err.syscall == "connect") {
+ if ("code" in err && err.code == "ECONNREFUSED") return "Error: " + err.message;
+ if ("code" in err && err.code == "ENOENT") return "Error: " + err.message;
+ }
+
+ return err;
+}
|