diff --git a/src/structures/Webhook.js b/src/structures/Webhook.js index b970f5addac6..ca3cb9533ce9 100644 --- a/src/structures/Webhook.js +++ b/src/structures/Webhook.js @@ -3,6 +3,8 @@ const path = require('path'); const Util = require('../util/Util'); const Attachment = require('./Attachment'); const RichEmbed = require('./RichEmbed'); +const Constants = require('../util/Constants'); +const Snowflake = require('../util/Snowflake'); /** * Represents a webhook. @@ -36,9 +38,9 @@ class Webhook extends EventEmitter { /** * The token for the webhook * @name Webhook#token - * @type {string} + * @type {?string} */ - Object.defineProperty(this, 'token', { value: data.token, writable: true, configurable: true }); + Object.defineProperty(this, 'token', { value: data.token || null, writable: true, configurable: true }); /** * The avatar for the webhook @@ -52,6 +54,12 @@ class Webhook extends EventEmitter { */ this.id = data.id; + /** + * The type of the webhook + * @type {WebhookTypes} + */ + this.type = Constants.WebhookTypes[data.type]; + /** * The guild the webhook belongs to * @type {Snowflake} @@ -75,6 +83,44 @@ class Webhook extends EventEmitter { } } + /** + * The timestamp the webhook was created at + * @type {number} + * @readonly + */ + get createdTimestamp() { + return Snowflake.deconstruct(this.id).timestamp; + } + + /** + * The time the webhook was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } + + /** + * A link to the webhook user's avatar + * @type {?stirng} + * @readonly + */ + get avatarURL() { + if (!this.avatar) return null; + return Constants.Endpoints.CDN(this.client.options.http.cdn).Avatar(this.id, this.avatar); + } + + /** + * The url of this webhook + * @type {string} + * @readonly + */ + get url() { + const API = `${this.client.options.http.host}/api/v${this.client.options.http.version}`; + return API + Constants.Endpoints.Webhook(this.id, this.token); + } + /** * Options that can be passed into send, sendMessage, sendFile, sendEmbed, and sendCode. * @typedef {Object} WebhookMessageOptions diff --git a/src/util/Constants.js b/src/util/Constants.js index 5053792a8fb1..3b841c53fcb4 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -902,3 +902,16 @@ exports.MembershipStates = [ 'INVITED', 'ACCEPTED', ]; + +/** + * The value set for a webhook's type: + * * Incoming + * * Channel Follower + * @typedef {string} WebhookTypes + */ +exports.WebhookTypes = [ + // They start at 1 + null, + 'Incoming', + 'Channel Follower', +]; diff --git a/typings/index.d.ts b/typings/index.d.ts index 7d1e3707e3c5..6bc16c347d76 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -1578,14 +1578,17 @@ declare module 'discord.js' { export class Webhook { constructor(client: Client, dataOrID: object | string, token: string); - public avatar: string; + public avatar: string | null; + public readonly avatarURL: string | null; public channelID: string; public readonly client: Client; public guildID: string; public id: Snowflake; public name: string; public owner: User | object; - public token: string; + public token: string | null; + public type: WebhookTypes; + public readonly url: string; public delete(reason?: string): Promise; public edit(name?: string, avatar?: BufferResolvable): Promise; public edit(options?: WebhookEditOptions, reason?: string): Promise; @@ -1604,6 +1607,7 @@ declare module 'discord.js' { private _timeouts: Set; private resolver: ClientDataResolver; private rest: object; + public token: string; public options: ClientOptions; public clearInterval(interval: NodeJS.Timer): void; @@ -2230,6 +2234,8 @@ declare module 'discord.js' { split?: boolean | SplitOptions; }; + type WebhookTypes = 'Incoming' | 'Channel Follower'; + type WebSocketOptions = { large_threshold?: number; compress?: boolean;