import { DISCORD_API_URL, DISCORD_API_VERSION } from '../consts/urlsAndVersions.ts' import { Client } from '../models/client.ts' import { RESTManager } from '../models/rest.ts' import { MessageOption } from '../types/channel.ts' import { UserPayload } from '../types/user.ts' import { WebhookPayload } from '../types/webhook.ts' import { Embed } from './embed.ts' import { Message } from './message.ts' import { TextChannel } from './textChannel.ts' import { User } from './user.ts' import { fetchAuto } from 'https://raw.githubusercontent.com/DjDeveloperr/fetch-base64/main/mod.ts' export interface WebhookMessageOptions extends MessageOption { embeds?: Embed[] name?: string avatar?: string } export type AllWebhookMessageOptions = string | WebhookMessageOptions export interface WebhookEditOptions { /** New name to set for Webhook. */ name?: string /** New avatar to set for Webhook. URL of image or base64 encoded data. */ avatar?: string /** New channel for Webhook. Requires authentication. */ channelID?: string } /** Webhook follows different way of instantiation */ export class Webhook { client?: Client id: string type: 1 | 2 guildID?: string channelID: string user?: User userRaw?: UserPayload name?: string avatar?: string token?: string applicationID?: string rest: RESTManager get url(): string { return `${DISCORD_API_URL}/v${DISCORD_API_VERSION}/webhooks/${this.id}/${this.token}` } constructor(data: WebhookPayload, client?: Client, rest?: RESTManager) { this.id = data.id this.type = data.type this.channelID = data.channel_id this.guildID = data.guild_id this.user = data.user === undefined || client === undefined ? undefined : new User(client, data.user) if (data.user !== undefined && client === undefined) this.userRaw = data.user this.name = data.name this.avatar = data.avatar this.token = data.token this.applicationID = data.application_id if (rest !== undefined) this.rest = rest else if (client !== undefined) this.rest = client.rest else this.rest = new RESTManager() } private fromPayload(data: WebhookPayload): Webhook { this.id = data.id this.type = data.type this.channelID = data.channel_id this.guildID = data.guild_id this.user = data.user === undefined || this.client === undefined ? undefined : new User(this.client, data.user) if (data.user !== undefined && this.client === undefined) this.userRaw = data.user this.name = data.name this.avatar = data.avatar this.token = data.token this.applicationID = data.application_id return this } /** Send a Message through Webhook. */ async send( text?: string | AllWebhookMessageOptions, option?: AllWebhookMessageOptions ): Promise { if (typeof text === 'object') { option = text text = undefined } if (text === undefined && option === undefined) { throw new Error('Either text or option is necessary.') } if (option instanceof Embed) option = { embeds: [option] } const payload: any = { content: text, embeds: (option as WebhookMessageOptions)?.embed !== undefined ? [(option as WebhookMessageOptions).embed] : (option as WebhookMessageOptions)?.embeds !== undefined ? (option as WebhookMessageOptions).embeds : undefined, file: (option as WebhookMessageOptions)?.file, tts: (option as WebhookMessageOptions)?.tts, allowed_mentions: (option as WebhookMessageOptions)?.allowedMentions } if ((option as WebhookMessageOptions)?.name !== undefined) { payload.username = (option as WebhookMessageOptions)?.name } if ((option as WebhookMessageOptions)?.avatar !== undefined) { payload.avatar = (option as WebhookMessageOptions)?.avatar } if ( payload.embeds !== undefined && payload.embeds instanceof Array && payload.embeds.length > 10 ) throw new Error(`Cannot send more than 10 embeds through Webhook`) const resp = await this.rest.post(this.url + '?wait=true', payload) const res = new Message( this.client as Client, resp, (this as unknown) as TextChannel, (this as unknown) as User ) await res.mentions.fromPayload(resp) return res } /** * Create a Webhook object from URL * @param url URL of the Webhook * @param client Client (bot) object, if any. */ static async fromURL(url: string | URL, client?: Client): Promise { const rest = client !== undefined ? client.rest : new RESTManager() const raw = await rest.get(typeof url === 'string' ? url : url.toString()) if (typeof raw !== 'object') throw new Error(`Failed to load Webhook from URL: ${url}`) const webhook = new Webhook(raw, client, rest) return webhook } /** * Edit the Webhook name, avatar, or channel (requires authentication). * @param options Options to edit the Webhook. */ async edit(options: WebhookEditOptions): Promise { if (options.channelID !== undefined && this.rest.client === undefined) throw new Error('Authentication is required for editing Webhook Channel') if ( options.avatar !== undefined && (options.avatar.startsWith('http:') || options.avatar.startsWith('https:')) ) { options.avatar = await fetchAuto(options.avatar) } const data = await this.rest.patch(this.url, options) this.fromPayload(data) return this } /** Delete the Webhook. */ async delete(): Promise { const resp = await this.rest.delete(this.url, undefined, 0, undefined, true) if (resp.response.status !== 204) return false else return true } }