@@ -3,6 +3,7 @@ import { Snowflake } from "discord-api-types/globals";
33import {
44 APIMessage ,
55 RESTGetAPIChannelWebhooksResult ,
6+ RESTJSONErrorCodes ,
67 RESTPostAPIChannelWebhookResult ,
78 RESTPostAPIWebhookWithTokenJSONBody ,
89 RESTPostAPIWebhookWithTokenWaitResult ,
@@ -54,6 +55,29 @@ export default class WebhookManager {
5455 } ,
5556 } ) ;
5657 }
58+ private _removeStoredWebhook (
59+ channelId : Snowflake ,
60+ guildId : Snowflake
61+ ) : Promise < unknown > {
62+ return this . _instance . prisma . channel . upsert ( {
63+ where : { id : BigInt ( channelId ) } ,
64+ update : { webhookId : null , webhookToken : null } ,
65+ create : {
66+ id : BigInt ( channelId ) ,
67+ webhookId : null ,
68+ webhookToken : null ,
69+ guild : {
70+ connectOrCreate : {
71+ where : { id : BigInt ( guildId ) } ,
72+
73+ create : {
74+ id : BigInt ( guildId ) ,
75+ } ,
76+ } ,
77+ } ,
78+ } ,
79+ } ) ;
80+ }
5781
5882 private async _getWebhookFromDiscord (
5983 channelId : Snowflake ,
@@ -120,6 +144,7 @@ export default class WebhookManager {
120144 }
121145 // If here this means that there are no webhooks that match the application id, and the token is null
122146 // Therefore we need to create a new webhook
147+
123148 return await this . _createWebhook ( channelId , guildId ) ;
124149 }
125150 private async _createWebhook (
@@ -138,7 +163,10 @@ export default class WebhookManager {
138163 ) ) as RESTPostAPIChannelWebhookResult ;
139164 } catch ( error ) {
140165 if ( error instanceof DiscordAPIError ) {
141- if ( error . code === 403 || error . code === 50013 ) {
166+ if (
167+ error . status === 403 ||
168+ error . code === RESTJSONErrorCodes . MissingPermissions
169+ ) {
142170 throw new UnexpectedFailure (
143171 InteractionOrRequestFinalStatus . BOT_MISSING_DISCORD_PERMISSION ,
144172 "Missing the permission `MANAGE_WEBHOOKS` on that channel"
@@ -193,15 +221,28 @@ export default class WebhookManager {
193221 files ?: RawFile [ ]
194222 ) : Promise < APIMessage > {
195223 const webhook = await this . getWebhook ( channelId , guildId ) ;
196-
197- const message = ( await this . _instance . restClient . post (
198- Routes . webhook ( webhook . id , webhook . token ) ,
199- {
200- body : data ,
201- files,
202- query : new URLSearchParams ( { wait : "true" } ) ,
224+ try {
225+ const message = ( await this . _instance . restClient . post (
226+ Routes . webhook ( webhook . id , webhook . token ) ,
227+ {
228+ body : data ,
229+ files,
230+ query : new URLSearchParams ( { wait : "true" } ) ,
231+ }
232+ ) ) as RESTPostAPIWebhookWithTokenWaitResult ;
233+ return message ;
234+ } catch ( error ) {
235+ if (
236+ error instanceof DiscordAPIError &&
237+ error . code === RESTJSONErrorCodes . UnknownWebhook
238+ ) {
239+ // If the webhook is not found, it means that it has been deleted, so we need to recreate it
240+ // First delete the webhook so it is not attempted to be used again, incase creating the webhook fails
241+ await this . _removeStoredWebhook ( channelId , guildId ) ;
242+ await this . _createWebhook ( channelId , guildId ) ;
243+ return await this . sendWebhookMessage ( channelId , guildId , data , files ) ;
203244 }
204- ) ) as RESTPostAPIWebhookWithTokenWaitResult ;
205- return message ;
245+ throw error ;
246+ }
206247 }
207248}
0 commit comments