├── src
├── mod.ts
├── classes
│ ├── Snowflake.ts
│ ├── Base.ts
│ ├── UnavailableGuild.ts
│ ├── GuildText.ts
│ ├── User.ts
│ ├── DMChannel.ts
│ ├── BaseChannel.ts
│ ├── GuildBan.ts
│ ├── BaseUser.ts
│ ├── ClientUser.ts
│ ├── MessageableChannel.ts
│ ├── GuildMember.ts
│ ├── Message.ts
│ └── Guild.ts
├── helpers
│ ├── waitUntil.ts
│ ├── Logger.ts
│ └── HTTPRequest.ts
├── stores
│ ├── BaseStore.ts
│ ├── PinnedMessageStore.ts
│ ├── GuildStore.ts
│ ├── DirectMessageStore.ts
│ ├── MessageStore.ts
│ ├── GuildBanStore.ts
│ ├── ChannelStore.ts
│ └── GuildMemberStore.ts
├── events
│ ├── GUILD_CREATE.ts
│ ├── GUILD_UPDATE.ts
│ ├── GUILD_DELETE.ts
│ ├── GUILD_MEMBER_REMOVE.ts
│ ├── GUILD_MEMBER_ADD.ts
│ ├── GUILD_BAN_ADD.ts
│ ├── GUILD_BAN_REMOVE.ts
│ ├── READY.ts
│ ├── CHANNEL_CREATE.ts
│ ├── CHANNEL_UPDATE.ts
│ ├── GUILD_MEMBER_UPDATE.ts
│ ├── MESSAGE_DELETE.ts
│ ├── MESSAGE_CREATE.ts
│ ├── CHANNEL_PINS_UPDATE.ts
│ └── MESSAGE_UPDATE.ts
└── Intents.ts
├── docs
├── assets
│ └── images
│ │ ├── icons.png
│ │ ├── icons@2x.png
│ │ ├── widgets.png
│ │ └── widgets@2x.png
└── modules
│ ├── intents.html
│ ├── classes_user.html
│ ├── classes_guild.html
│ ├── helpers_logger.html
│ ├── classes_base.html
│ ├── classes_dmchannel.html
│ ├── classes_baseuser.html
│ ├── classes_snowflake.html
│ ├── classes_message.html
│ ├── stores_guildstore.html
│ ├── classes_basechannel.html
│ ├── classes_guildban.html
│ ├── stores_channelstore.html
│ ├── stores_basestore.html
│ ├── classes_guildmember.html
│ ├── stores_messagestore.html
│ ├── classes_unavailableguild.html
│ ├── stores_guildbanstore.html
│ ├── stores_directmessagestore.html
│ ├── stores_guildmemberstore.html
│ ├── stores_pinnedmessagestore.html
│ ├── classes_guildtext.html
│ ├── classes_clientuser.html
│ ├── client.html
│ ├── classes_messageablechannel.html
│ ├── events_ready.html
│ └── events_guild_create.html
├── .prettierrc
├── .swcrc
├── scripts
├── semver.js
└── d.ts.js
├── .github
└── workflows
│ ├── devel.yml
│ ├── main.yml
│ └── codeql-analysis.yml
├── tsconfig.json
├── .eslintrc
├── README.md
├── .gitignore
└── package.json
/src/mod.ts:
--------------------------------------------------------------------------------
1 | export * from './Client';
2 | export * from './Intents';
3 |
--------------------------------------------------------------------------------
/docs/assets/images/icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ItsRauf/esmcord/HEAD/docs/assets/images/icons.png
--------------------------------------------------------------------------------
/docs/assets/images/icons@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ItsRauf/esmcord/HEAD/docs/assets/images/icons@2x.png
--------------------------------------------------------------------------------
/docs/assets/images/widgets.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ItsRauf/esmcord/HEAD/docs/assets/images/widgets.png
--------------------------------------------------------------------------------
/docs/assets/images/widgets@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ItsRauf/esmcord/HEAD/docs/assets/images/widgets@2x.png
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "bracketSpacing": true,
3 | "singleQuote": true,
4 | "trailingComma": "es5",
5 | "arrowParens": "avoid",
6 | "semi": true,
7 | "tabWidth": 2
8 | }
9 |
--------------------------------------------------------------------------------
/src/classes/Snowflake.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @export
3 | * @class Snowflake
4 | */
5 | export class Snowflake {
6 | constructor(public id: string) {}
7 | public get asUser(): string {
8 | return `<@!${this.id}>`;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/helpers/waitUntil.ts:
--------------------------------------------------------------------------------
1 | export function waitUntil(condition: () => boolean): Promise {
2 | const poll = (resolve: (value: void) => void) => {
3 | if (condition()) resolve();
4 | else setTimeout(() => poll(resolve), 400);
5 | };
6 |
7 | return new Promise(poll);
8 | }
9 |
--------------------------------------------------------------------------------
/src/helpers/Logger.ts:
--------------------------------------------------------------------------------
1 | import color from 'ansi-colors';
2 |
3 | export class Logger {
4 | static debug(message: string, ...optionalData: unknown[]): void {
5 | console.debug(
6 | `${color.bold(color.gray('[DEBUG]:'))} ${message}`,
7 | ...optionalData
8 | );
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/stores/BaseStore.ts:
--------------------------------------------------------------------------------
1 | import { Base } from '../classes/Base';
2 | import { Client } from '../Client';
3 |
4 | export abstract class BaseStore<
5 | T extends Base>
6 | > extends Map {
7 | constructor(protected $: Client) {
8 | super();
9 | }
10 |
11 | abstract fetch(id: T['id']): Promise;
12 |
13 | array(): T[] {
14 | return Array.from(this.values());
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/events/GUILD_CREATE.ts:
--------------------------------------------------------------------------------
1 | import { Client } from '../Client';
2 | import { GatewayGuildCreateDispatch } from 'discord-api-types/v8';
3 | import { Guild } from '../classes/Guild';
4 |
5 | export default function ($: Client, data: GatewayGuildCreateDispatch): void {
6 | const guild = new Guild($, {
7 | ...data.d,
8 | unavailable: data.d.unavailable ?? false,
9 | });
10 | $.guilds.set(guild.id, guild);
11 | $.emit('GuildCreate', guild);
12 | }
13 |
--------------------------------------------------------------------------------
/.swcrc:
--------------------------------------------------------------------------------
1 | {
2 | "minify": false,
3 | "jsc": {
4 | "target": "es2020",
5 | "loose": false,
6 | "parser": {
7 | "syntax": "typescript",
8 | "dynamicImport": true,
9 | "tsx": false,
10 | "decorators": true
11 | },
12 | "transform": {
13 | "legacyDecorator": true,
14 | "decoratorMetadata": true
15 | }
16 | },
17 | "module": {
18 | "type": "es6",
19 | "strict": true,
20 | "lazy": false
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/events/GUILD_UPDATE.ts:
--------------------------------------------------------------------------------
1 | import { Client } from '../Client';
2 | import { GatewayGuildUpdateDispatch } from 'discord-api-types/v8';
3 | import { Guild } from '../classes/Guild';
4 |
5 | export default async function (
6 | $: Client,
7 | data: GatewayGuildUpdateDispatch
8 | ): Promise {
9 | const oldGuild = $.guilds.get(data.d.id) as Guild;
10 | const newGuild = new Guild($, data.d);
11 | $.guilds.set(newGuild.id, newGuild);
12 | $.emit('GuildUpdate', oldGuild, newGuild);
13 | }
14 |
--------------------------------------------------------------------------------
/src/events/GUILD_DELETE.ts:
--------------------------------------------------------------------------------
1 | import { Client } from '../Client';
2 | import { GatewayGuildDeleteDispatch } from 'discord-api-types/v8';
3 | import { UnavailableGuild } from '../classes/UnavailableGuild';
4 |
5 | export default async function (
6 | $: Client,
7 | data: GatewayGuildDeleteDispatch
8 | ): Promise {
9 | const guild = $.guilds.get(data.d.id) as UnavailableGuild;
10 | if (!data.d.unavailable) {
11 | $.guilds.delete(guild.id);
12 | }
13 | $.emit('GuildDelete', guild);
14 | }
15 |
--------------------------------------------------------------------------------
/src/events/GUILD_MEMBER_REMOVE.ts:
--------------------------------------------------------------------------------
1 | import { Client } from '../Client';
2 | import { GatewayGuildMemberRemoveDispatch } from 'discord-api-types/v8';
3 | import { Guild } from '../classes/Guild';
4 |
5 | export default function (
6 | $: Client,
7 | data: GatewayGuildMemberRemoveDispatch
8 | ): void {
9 | const guild = $.guilds.get(data.d.guild_id) as Guild;
10 | if (!guild.unavailable) {
11 | const guildMember = guild.members.get(data.d.user.id);
12 | $.emit('GuildMemberRemove', guildMember!);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Intents.ts:
--------------------------------------------------------------------------------
1 | export enum Intents {
2 | GUILDS = 1 << 0,
3 | GUILD_MEMBERS = 1 << 1,
4 | GUILD_BANS = 1 << 2,
5 | GUILD_EMOJIS = 1 << 3,
6 | GUILD_INTEGRATIONS = 1 << 4,
7 | GUILD_WEBHOOKS = 1 << 5,
8 | GUILD_INVITES = 1 << 6,
9 | GUILD_VOICE_STATES = 1 << 7,
10 | GUILD_PRESENCES = 1 << 8,
11 | GUILD_MESSAGES = 1 << 9,
12 | GUILD_MESSAGE_REACTIONS = 1 << 10,
13 | GUILD_MESSAGE_TYPING = 1 << 11,
14 | DIRECT_MESSAGES = 1 << 12,
15 | DIRECT_MESSAGE_REACTIONS = 1 << 13,
16 | DIRECT_MESSAGE_TYPING = 1 << 14,
17 | }
18 |
--------------------------------------------------------------------------------
/src/classes/Base.ts:
--------------------------------------------------------------------------------
1 | import { Client } from '../Client';
2 |
3 | /**
4 | * Base Class (internal use only)
5 | *
6 | * @export
7 | * @class Base
8 | * @template T
9 | * @abstract
10 | */
11 | export abstract class Base {
12 | [key: string]: unknown;
13 | /**
14 | * Creates an instance of Base.
15 | * @param {T} data
16 | * @memberof Base
17 | */
18 | constructor(protected $: Client, data: T) {
19 | Object.assign(this, data);
20 | }
21 |
22 | abstract edit(data: Record): Promise;
23 | }
24 |
--------------------------------------------------------------------------------
/src/events/GUILD_MEMBER_ADD.ts:
--------------------------------------------------------------------------------
1 | import { Client } from '../Client';
2 | import { GatewayGuildMemberAddDispatch } from 'discord-api-types/v8';
3 | import { Guild } from '../classes/Guild';
4 | import { GuildMember } from '../classes/GuildMember';
5 |
6 | export default function ($: Client, data: GatewayGuildMemberAddDispatch): void {
7 | const guild = $.guilds.get(data.d.guild_id) as Guild;
8 | if (!guild.unavailable) {
9 | const guildMember = new GuildMember($, guild, data.d);
10 | guild.members.set(guildMember.id, guildMember);
11 | $.emit('GuildMemberAdd', guildMember);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/events/GUILD_BAN_ADD.ts:
--------------------------------------------------------------------------------
1 | import { Client } from '../Client';
2 | import { GatewayGuildBanAddDispatch } from 'discord-api-types/v8';
3 | import { Guild } from '../classes/Guild';
4 | import { GuildBan } from '../classes/GuildBan';
5 |
6 | export default function ($: Client, data: GatewayGuildBanAddDispatch): void {
7 | const guild = $.guilds.get(data.d.guild_id) as Guild;
8 | const ban = new GuildBan($, guild, { user: data.d.user, reason: '' });
9 | if (!guild.bans.has(ban.id)) {
10 | guild.bans.set(ban.id, ban);
11 | $.emit('GuildBanAdd', ban);
12 | } else {
13 | const exisingBan = guild.bans.get(ban.id)!;
14 | $.emit('GuildBanAdd', exisingBan);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/events/GUILD_BAN_REMOVE.ts:
--------------------------------------------------------------------------------
1 | import { Client } from '../Client';
2 | import { GatewayGuildBanRemoveDispatch } from 'discord-api-types/v8';
3 | import { Guild } from '../classes/Guild';
4 | import { GuildBan } from '../classes/GuildBan';
5 |
6 | export default function ($: Client, data: GatewayGuildBanRemoveDispatch): void {
7 | const guild = $.guilds.get(data.d.guild_id) as Guild;
8 | const ban = new GuildBan($, guild, { user: data.d.user, reason: '' });
9 | if (guild.bans.has(ban.id)) {
10 | const existing = guild.bans.get(ban.id)!;
11 | guild.bans.delete(existing.id);
12 | $.emit('GuildBanRemove', existing);
13 | } else {
14 | $.emit('GuildBanRemove', ban);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/events/READY.ts:
--------------------------------------------------------------------------------
1 | import { Client } from '../Client';
2 | import { ClientUser } from '../classes/ClientUser';
3 | import { GatewayReadyDispatch } from 'discord-api-types/v8';
4 | import { UnavailableGuild } from '../classes/UnavailableGuild';
5 |
6 | export default function ($: Client, data: GatewayReadyDispatch): void {
7 | $._sessionID = data.d.session_id;
8 | $.user = new ClientUser($, {
9 | ...data.d.user,
10 | application: data.d.application,
11 | });
12 | data.d.guilds.map(g => {
13 | const guild = new UnavailableGuild($, {
14 | ...g,
15 | });
16 | $.guilds.set(guild.id, guild);
17 | });
18 | $.emit('Ready', new Date());
19 | $._connected = true;
20 | }
21 |
--------------------------------------------------------------------------------
/scripts/semver.js:
--------------------------------------------------------------------------------
1 | import { readFile, writeFile } from 'fs/promises';
2 | import semver from 'semver';
3 |
4 | (async () => {
5 | const packageJSON = await readFile('./package.json');
6 | const { name, version, ...pkg } = JSON.parse(packageJSON);
7 | const commits = process.env.GitHubCommits
8 | ? JSON.parse(process.env.GitHubCommits)
9 | : [];
10 | let rel = 'patch';
11 | if (commits.length <= 10) {
12 | rel = 'patch';
13 | } else if (commits.length <= 50) {
14 | rel = 'minor';
15 | } else {
16 | rel = 'major';
17 | }
18 | const semverVersion = semver.inc(version, rel);
19 | await writeFile(
20 | './package.json',
21 | JSON.stringify({ name, version: semverVersion, ...pkg }, null, 2)
22 | );
23 | console.log(semverVersion);
24 | })();
25 |
--------------------------------------------------------------------------------
/.github/workflows/devel.yml:
--------------------------------------------------------------------------------
1 | name: Devel Workflow
2 |
3 | on:
4 | push:
5 | branches: [devel]
6 | pull_request:
7 | branches: [main]
8 |
9 | jobs:
10 | compile:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v2
14 | - name: Use Node
15 | uses: actions/setup-node@v1
16 | with:
17 | node-version: 15.x
18 | - uses: pnpm/action-setup@v2.0.1
19 | with:
20 | version: 6.3.0
21 | - name: pnpm storage cache
22 | uses: actions/cache@v2
23 | with:
24 | path: ~/.pnpm-store/v3
25 | key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
26 | - name: pnpm install
27 | run: pnpm i --frozen-lockfile
28 | - name: Lint
29 | run: pnpm run precompile
30 |
--------------------------------------------------------------------------------
/src/classes/UnavailableGuild.ts:
--------------------------------------------------------------------------------
1 | import { APIUnavailableGuild } from 'discord-api-types/v8';
2 | import { Client } from '../Client';
3 | import { Base } from './Base';
4 | import { Snowflake } from './Snowflake';
5 |
6 | export interface UnavailableGuild extends APIUnavailableGuild {
7 | [key: string]: unknown;
8 | }
9 |
10 | /**
11 | * @export
12 | * @class UnavailableGuild
13 | * @extends {Base}
14 | */
15 | export class UnavailableGuild extends Base {
16 | public snowflake: Snowflake;
17 |
18 | constructor($: Client, data: APIUnavailableGuild) {
19 | super($, data);
20 | this.snowflake = new Snowflake(this.id);
21 | }
22 |
23 | edit(): Promise {
24 | return Promise.reject(new Error('Edit not allowed on this Class'));
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/classes/GuildText.ts:
--------------------------------------------------------------------------------
1 | import { Client } from '../Client';
2 | import { Guild } from './Guild';
3 | import {
4 | MessageableChannel,
5 | MessageableChannelData,
6 | } from './MessageableChannel';
7 |
8 | export interface GuildTextData extends MessageableChannelData {
9 | owner_id?: never | undefined;
10 | }
11 |
12 | export interface GuildText extends GuildTextData {
13 | [key: string]: unknown;
14 | owner_id: never;
15 | }
16 |
17 | /**
18 | * @export
19 | * @class GuildText
20 | * @extends {MessageableChannel}
21 | */
22 | export class GuildText extends MessageableChannel {
23 | constructor(protected $: Client, public guild: Guild, data: GuildTextData) {
24 | super($, data);
25 | }
26 |
27 | edit(): Promise {
28 | throw new Error('Method not implemented.');
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowUnreachableCode": false,
4 | "allowUnusedLabels": false,
5 | "declaration": true,
6 | "declarationMap": true,
7 | "emitDeclarationOnly": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "lib": ["ESNext"],
10 | "module": "ESNext",
11 | "moduleResolution": "Node",
12 | "allowSyntheticDefaultImports": true,
13 | "noEmitOnError": true,
14 | "noFallthroughCasesInSwitch": true,
15 | "noImplicitAny": true,
16 | "noImplicitReturns": true,
17 | "pretty": true,
18 | "rootDir": "src",
19 | "resolveJsonModule": true,
20 | "sourceMap": true,
21 | "strict": true,
22 | "target": "ESNext"
23 | },
24 | "include": ["src/**/*.ts", "typings/**/*.ts"],
25 | "exclude": ["node_modules", "build"]
26 | }
27 |
--------------------------------------------------------------------------------
/src/events/CHANNEL_CREATE.ts:
--------------------------------------------------------------------------------
1 | import { Client } from '../Client';
2 | import { GatewayChannelCreateDispatch } from 'discord-api-types/v8';
3 | import { GuildText } from '../classes/GuildText';
4 | import { Guild } from '../classes/Guild';
5 |
6 | export default async function (
7 | $: Client,
8 | data: GatewayChannelCreateDispatch
9 | ): Promise {
10 | if (data.d.guild_id) {
11 | let guild = $.guilds.get(data.d.guild_id);
12 | if (!guild) guild = await $.guilds.fetch(data.d.guild_id);
13 | if (guild.unavailable) guild = await $.guilds.fetch(data.d.guild_id);
14 | const channel = new GuildText($, guild as Guild, {
15 | ...data.d,
16 | owner_id: undefined,
17 | });
18 | (guild as Guild).channels.set(channel.id, channel);
19 | $.emit('ChannelCreate', channel);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/events/CHANNEL_UPDATE.ts:
--------------------------------------------------------------------------------
1 | import { Client } from '../Client';
2 | import { GatewayChannelUpdateDispatch } from 'discord-api-types/v8';
3 | import { GuildText } from '../classes/GuildText';
4 | import { Guild } from '../classes/Guild';
5 |
6 | export default async function (
7 | $: Client,
8 | data: GatewayChannelUpdateDispatch
9 | ): Promise {
10 | if (data.d.guild_id) {
11 | let guild = $.guilds.get(data.d.guild_id);
12 | if (!guild) guild = await $.guilds.fetch(data.d.guild_id);
13 | const oldChannel = (guild as Guild).channels.get(data.d.id)!;
14 | const newChannel = new GuildText($, guild as Guild, {
15 | ...data.d,
16 | owner_id: undefined,
17 | });
18 | (guild as Guild).channels.set(newChannel.id, newChannel);
19 | $.emit('ChannelUpdate', oldChannel, newChannel);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/stores/PinnedMessageStore.ts:
--------------------------------------------------------------------------------
1 | import { RESTGetAPIChannelPinsResult } from 'discord-api-types/v8';
2 | import { Message } from '../classes/Message';
3 | import { MessageableChannel } from '../classes/MessageableChannel';
4 | import { MessageStore } from './MessageStore';
5 |
6 | export class PinnedMessageStore<
7 | C extends MessageableChannel
8 | > extends MessageStore {
9 | async fetchAll(): Promise[]> {
10 | try {
11 | const res = await this.$.http('GET', `/channels/${this.channel.id}/pins`);
12 | const messages: RESTGetAPIChannelPinsResult = await res.json();
13 | const msgs = messages.map(m => new Message(this.$, this.channel, m));
14 | msgs.forEach(m => {
15 | this.channel.messages.set(m.id, m);
16 | this.channel.pins.set(m.id, m);
17 | });
18 | return msgs;
19 | } catch (error) {
20 | return Promise.reject(error);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/classes/User.ts:
--------------------------------------------------------------------------------
1 | import { BaseUser } from './BaseUser';
2 | import { DMChannel } from './DMChannel';
3 |
4 | export class User extends BaseUser {
5 | edit(): Promise {
6 | return Promise.reject(new Error('Edit not allowed on this Class'));
7 | }
8 |
9 | /**
10 | * Creates a DM with the current user
11 | * {@link https://discord.com/developers/docs/resources/user#create-dm}
12 | *
13 | * ---
14 | * @param {boolean} [cached=true]
15 | * @return {*} {Promise}
16 | * @memberof User
17 | */
18 | async createDM(cached = true): Promise {
19 | try {
20 | const existing = this.$.directMessages
21 | .array()
22 | .find(channel => channel.recipients?.includes(this));
23 | if (existing && cached) {
24 | return existing;
25 | } else {
26 | return this.$.directMessages.fetch(this.id);
27 | }
28 | } catch (error) {
29 | return Promise.reject(error);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/helpers/HTTPRequest.ts:
--------------------------------------------------------------------------------
1 | import centra from 'centra';
2 |
3 | const BASE_URL = 'https://discord.com/api/v9';
4 |
5 | /**
6 | * Helper function for HTTP Requests
7 | *
8 | * @export
9 | * @param {centra.Request['method']} method HTTP method (get, post, put, patch, delete)
10 | * @param {string} endpoint Request Endpoint
11 | * @param {Record} data Request Body (json)
12 | * @param {string} _token
13 | * @returns {Promise}
14 | */
15 | export function HTTPRequest(
16 | this: { token: string },
17 | method: centra.Request['method'],
18 | endpoint: string,
19 | data?: Record,
20 | query?: Record
21 | ): Promise {
22 | let req = centra(`${BASE_URL}/${endpoint}`, method)
23 | .timeout(10000)
24 | .header({
25 | 'Content-Type': 'application/json',
26 | Authorization: `Bot ${this.token}`,
27 | });
28 | if (query) req = req.query(query);
29 | if (data) req = req.body(data, 'json');
30 | return req.send();
31 | }
32 |
--------------------------------------------------------------------------------
/src/stores/GuildStore.ts:
--------------------------------------------------------------------------------
1 | import { RESTGetAPIGuildResult } from 'discord-api-types/v8';
2 | import { Guild } from '../classes/Guild';
3 | import { UnavailableGuild } from '../classes/UnavailableGuild';
4 | import { Client } from '../Client';
5 | import { BaseStore } from './BaseStore';
6 |
7 | export class GuildStore extends BaseStore {
8 | constructor($: Client) {
9 | super($);
10 | }
11 | /**
12 | * {@link https://discord.com/developers/docs/resources/guild#get-guild}
13 | *
14 | * ---
15 | * @param {Guild['id']} id
16 | * @return {*} {Promise}
17 | * @memberof GuildStore
18 | */
19 | async fetch(id: Guild['id']): Promise {
20 | try {
21 | const res = await this.$.http('GET', `/guilds/${id}`);
22 | const guildJSON: RESTGetAPIGuildResult = await res.json();
23 | const guild = new Guild(this.$, {
24 | ...guildJSON,
25 | });
26 | this.set(guild.id, guild);
27 | return guild;
28 | } catch (error) {
29 | return Promise.reject(error);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/events/GUILD_MEMBER_UPDATE.ts:
--------------------------------------------------------------------------------
1 | import { Client } from '../Client';
2 | import { GatewayGuildMemberUpdateDispatch } from 'discord-api-types/v8';
3 | import { Guild } from '../classes/Guild';
4 | import { GuildMember } from '../classes/GuildMember';
5 |
6 | export default function (
7 | $: Client,
8 | data: GatewayGuildMemberUpdateDispatch
9 | ): void {
10 | const guild = $.guilds.get(data.d.guild_id) as Guild;
11 | if (guild.members) {
12 | if (guild.members.has(data.d.user!.id)) {
13 | const oldMember = guild.members.get(data.d.user!.id);
14 | const newMember = new GuildMember($, guild, {
15 | ...data.d,
16 | deaf: oldMember?.deaf,
17 | mute: oldMember?.mute,
18 | });
19 | guild.members.set(newMember.id, newMember);
20 | $.emit('GuildMemberUpdate', newMember, oldMember);
21 | } else {
22 | const newMember = new GuildMember($, guild, {
23 | ...data.d,
24 | deaf: undefined,
25 | mute: undefined,
26 | });
27 | guild.members.set(newMember.id, newMember);
28 | $.emit('GuildMemberUpdate', newMember);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/classes/DMChannel.ts:
--------------------------------------------------------------------------------
1 | import { ChannelType, RESTDeleteAPIChannelResult } from 'discord-api-types/v8';
2 | import { Client } from '../Client';
3 | import {
4 | MessageableChannel,
5 | MessageableChannelData,
6 | } from './MessageableChannel';
7 |
8 | export interface DMChannel extends MessageableChannel {
9 | type: ChannelType.DM;
10 | guild_id?: never;
11 | delete: never;
12 | }
13 |
14 | /**
15 | * Direct Message Channel
16 | *
17 | * @export
18 | * @class DMChannel
19 | * @extends {MessageableChannel}
20 | */
21 | export class DMChannel extends MessageableChannel {
22 | constructor(protected $: Client, data: MessageableChannelData) {
23 | super($, data);
24 | }
25 |
26 | edit(): Promise {
27 | return Promise.reject(new Error('Update not allowed on this Class'));
28 | }
29 |
30 | /**
31 | * {@link https://discord.com/developers/docs/resources/channel#deleteclose-channel}
32 | *
33 | * ---
34 | * @return {*} {Promise}
35 | * @memberof DMChannel
36 | */
37 | async close(): Promise {
38 | return super.delete();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/classes/BaseChannel.ts:
--------------------------------------------------------------------------------
1 | import { APIChannel, RESTDeleteAPIChannelResult } from 'discord-api-types/v8';
2 | import { Client } from '../Client';
3 | import { Base } from './Base';
4 |
5 | export interface BaseChannel extends APIChannel {
6 | [key: string]: unknown;
7 | }
8 |
9 | /**
10 | * {@link https://discord.com/developers/docs/resources/channel#channel-object}
11 | *
12 | * @export
13 | * @abstract
14 | * @class BaseChannel
15 | * @extends {Base}
16 | */
17 | export abstract class BaseChannel extends Base {
18 | constructor($: Client, data: APIChannel) {
19 | super($, data);
20 | }
21 |
22 | abstract edit(data: Record): Promise;
23 |
24 | /**
25 | * {@link https://discord.com/developers/docs/resources/channel#deleteclose-channel}
26 | *
27 | * ---
28 | * @return {*} {Promise}
29 | * @memberof BaseChannel
30 | */
31 | async delete(): Promise {
32 | try {
33 | const res = await this.$.http('DELETE', `/channels/${this.id}`);
34 | return await res.json();
35 | } catch (error) {
36 | return Promise.reject(error);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/events/MESSAGE_DELETE.ts:
--------------------------------------------------------------------------------
1 | import { Client } from '../Client';
2 | import { GatewayMessageDeleteDispatch } from 'discord-api-types/v8';
3 | import { Guild } from '../classes/Guild';
4 |
5 | export default async function (
6 | $: Client,
7 | data: GatewayMessageDeleteDispatch
8 | ): Promise {
9 | if (data.d.guild_id) {
10 | const guild = $.guilds.get(data.d.guild_id);
11 | if (guild instanceof Guild) {
12 | const channel = guild.channels.get(data.d.channel_id);
13 | if (channel) {
14 | const message = channel.messages.get(data.d.id);
15 | if (message) channel.messages.delete(message.id);
16 | $.emit('MessageDelete', message);
17 | } else {
18 | await guild.channels.fetch(data.d.channel_id);
19 | $.emit('MessageDelete');
20 | }
21 | }
22 | } else {
23 | const channel = $.directMessages.get(data.d.channel_id);
24 | if (channel) {
25 | const message = channel.messages.get(data.d.id);
26 | if (message) channel.messages.delete(message.id);
27 | $.emit('DirectMessageDelete', message);
28 | } else {
29 | await $.directMessages.fetch(data.d.channel_id);
30 | $.emit('DirectMessageDelete');
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/classes/GuildBan.ts:
--------------------------------------------------------------------------------
1 | import { APIBan } from 'discord-api-types/v8';
2 | import { Client } from '../Client';
3 | import { Base } from './Base';
4 | import { Guild } from './Guild';
5 |
6 | interface APIBanWithOptionalUser extends Omit {
7 | user?: APIBan['user'];
8 | }
9 |
10 | export interface GuildBan extends APIBanWithOptionalUser {
11 | guild: G;
12 | id?: APIBan['user']['id'];
13 | }
14 |
15 | export class GuildBan extends Base {
16 | constructor(
17 | protected $: Client,
18 | public guild: G,
19 | data: APIBanWithOptionalUser
20 | ) {
21 | super($, data);
22 | this.id = data.user?.id;
23 | }
24 | edit(): Promise {
25 | throw new Error('Method not implemented.');
26 | }
27 |
28 | /**
29 | * {@link https://discord.com/developers/docs/resources/guild#remove-guild-ban}
30 | *
31 | * ---
32 | * @return {*} {Promise}
33 | * @memberof GuildBan
34 | */
35 | async unban(): Promise {
36 | try {
37 | await this.$.http('DELETE', `/guilds/${this.guild.id}/bans/${this.id}`);
38 | this.guild.bans.delete(this.id);
39 | } catch (error) {
40 | return Promise.reject(error);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/stores/DirectMessageStore.ts:
--------------------------------------------------------------------------------
1 | import { ChannelType, RESTGetAPIChannelResult } from 'discord-api-types/v8';
2 | import { DMChannel } from '../classes/DMChannel';
3 | import { Client } from '../Client';
4 | import { BaseStore } from './BaseStore';
5 |
6 | export class DirectMessageStore extends BaseStore {
7 | constructor($: Client) {
8 | super($);
9 | }
10 |
11 | /**
12 | * {@link https://discord.com/developers/docs/resources/channel#get-channel}
13 | *
14 | * ---
15 | * @param {DMChannel['id']} id
16 | * @return {*} {Promise}
17 | * @memberof DirectMessageStore
18 | */
19 | async fetch(id: DMChannel['id']): Promise {
20 | try {
21 | const res = await this.$.http('GET', `/channels/${id}`);
22 | const dmJSON: RESTGetAPIChannelResult = await res.json();
23 | if (dmJSON.type === ChannelType.DM) {
24 | const dm = new DMChannel(this.$, {
25 | ...dmJSON,
26 | type: ChannelType.DM,
27 | guild_id: undefined,
28 | });
29 | this.set(dm.id, dm);
30 | return dm;
31 | } else return Promise.reject(new Error('Channel is not of type DM'));
32 | } catch (error) {
33 | return Promise.reject(error);
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/stores/MessageStore.ts:
--------------------------------------------------------------------------------
1 | import { RESTGetAPIChannelMessageResult } from 'discord-api-types/v8';
2 | import { Message } from '../classes/Message';
3 | import { MessageableChannel } from '../classes/MessageableChannel';
4 | import { Client } from '../Client';
5 | import { BaseStore } from './BaseStore';
6 |
7 | export class MessageStore extends BaseStore<
8 | Message
9 | > {
10 | constructor($: Client, protected channel: C) {
11 | super($);
12 | }
13 | /**
14 | * {@link https://discord.com/developers/docs/resources/channel#get-channel-message}
15 | *
16 | * ---
17 | * @param {Message['id']} id
18 | * @return {*} {Promise>}
19 | * @memberof MessageStore
20 | */
21 | async fetch(id: Message['id']): Promise> {
22 | try {
23 | const res = await this.$.http(
24 | 'GET',
25 | `/channels/${this.channel.id}/messages/${id}`
26 | );
27 | const messageJSON: RESTGetAPIChannelMessageResult = await res.json();
28 | const message = new Message(this.$, this.channel, {
29 | ...messageJSON,
30 | });
31 | this.set(message.id, message);
32 | return message;
33 | } catch (error) {
34 | return Promise.reject(error);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/classes/BaseUser.ts:
--------------------------------------------------------------------------------
1 | import { APIUser } from 'discord-api-types/v8';
2 | import { Client } from '../Client';
3 | import { Base } from './Base';
4 | import { Snowflake } from './Snowflake';
5 |
6 | export interface BaseUser extends APIUser {
7 | [key: string]: unknown;
8 | }
9 |
10 | /**
11 | * {@link https://discord.com/developers/docs/resources/user#user-object}
12 | *
13 | * @export
14 | * @abstract
15 | * @class BaseUser
16 | * @extends {Base}
17 | */
18 | export abstract class BaseUser extends Base {
19 | public snowflake: Snowflake;
20 |
21 | constructor($: Client, data: APIUser) {
22 | super($, data);
23 | this.snowflake = new Snowflake(data.id);
24 | }
25 |
26 | /**
27 | * The discord "tag" for this user (ex. `Rauf#3543`)
28 | *
29 | * @readonly
30 | * @type {string}
31 | * @memberof BaseUser
32 | */
33 | public get tag(): string {
34 | return `${this.username}#${this.discriminator}`;
35 | }
36 |
37 | /**
38 | * The discord mention for this user (ex. `@Rauf#3543`)
39 | *
40 | * @readonly
41 | * @type {string}
42 | * @memberof BaseUser
43 | */
44 | public get mention(): string {
45 | return this.snowflake.asUser;
46 | }
47 |
48 | abstract edit(data: Record): Promise;
49 | }
50 |
--------------------------------------------------------------------------------
/scripts/d.ts.js:
--------------------------------------------------------------------------------
1 | import { resolve, sep } from 'path';
2 |
3 | import glob from 'fast-glob';
4 | import { performance } from 'perf_hooks';
5 | import ts from 'typescript';
6 | import { writeFile } from 'fs/promises';
7 |
8 | const start = performance.now();
9 |
10 | console.log('Type Declaration Generator\n');
11 |
12 | /** @type {Map} */
13 | const declarations = new Map();
14 | const options = {
15 | declaration: true,
16 | declarationMap: true,
17 | emitDeclarationOnly: true,
18 | };
19 | // const options = JSON.parse(await readFile('tsconfig.json'));
20 | const host = ts.createCompilerHost(options);
21 | host.writeFile = (filename, contents) => declarations.set(filename, contents);
22 |
23 | console.info('Finding .ts files');
24 | const filenames = glob.sync('src/**/*.ts');
25 |
26 | const compiler = ts.createProgram(filenames, options, host);
27 | console.info('Compiling .ts files');
28 | compiler.emit();
29 |
30 | const declarationEntries = [...declarations.entries()];
31 | console.info('Writing .d.ts files\n');
32 | const cwd = process.cwd().replace(new RegExp(sep.repeat(2), 'g'), '/');
33 | for (const [path, content] of declarationEntries) {
34 | const buildPath = path.startsWith(cwd)
35 | ? path.substr(cwd.length + 1).split('/')
36 | : path.split('/');
37 | buildPath.shift();
38 | writeFile(resolve(cwd, 'build', ...buildPath), content);
39 | }
40 | const end = performance.now();
41 | console.info(
42 | `Successfully generated ${declarationEntries.length} type declaration${
43 | declarationEntries.length === 1 ? '' : 's'
44 | }. (${Math.floor(end - start)}ms)`
45 | );
46 |
--------------------------------------------------------------------------------
/src/events/MESSAGE_CREATE.ts:
--------------------------------------------------------------------------------
1 | import { Client } from '../Client';
2 | import { GatewayMessageCreateDispatch } from 'discord-api-types/v8';
3 | import { Message } from '../classes/Message';
4 | import { Guild } from '../classes/Guild';
5 |
6 | export default async function (
7 | $: Client,
8 | data: GatewayMessageCreateDispatch
9 | ): Promise {
10 | if (data.d.guild_id) {
11 | let guild = $.guilds.get(data.d.guild_id);
12 | if (guild?.unavailable) guild = await $.guilds.fetch(data.d.guild_id);
13 | if (guild instanceof Guild) {
14 | const channel = guild.channels.get(data.d.channel_id);
15 | if (channel) {
16 | const message = new Message($, channel, {
17 | ...data.d,
18 | });
19 | channel.messages.set(message.id, message);
20 | $.emit('MessageCreate', message);
21 | } else {
22 | const chan = await guild.channels.fetch(data.d.channel_id);
23 | const message = new Message($, chan, {
24 | ...data.d,
25 | });
26 | chan.messages.set(message.id, message);
27 | $.emit('MessageCreate', message);
28 | }
29 | }
30 | } else {
31 | const channel = $.directMessages.get(data.d.channel_id);
32 | if (channel) {
33 | const message = new Message($, channel, {
34 | ...data.d,
35 | });
36 | channel.messages.set(message.id, message);
37 | $.emit('DirectMessageCreate', message);
38 | } else {
39 | const dm = await $.directMessages.fetch(data.d.channel_id);
40 | const message = new Message($, dm, {
41 | ...data.d,
42 | });
43 | dm.messages.set(message.id, message);
44 | $.emit('DirectMessageCreate', message);
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/events/CHANNEL_PINS_UPDATE.ts:
--------------------------------------------------------------------------------
1 | import { GatewayChannelPinsUpdateDispatch } from 'discord-api-types/v8';
2 | import { Guild } from '../classes/Guild';
3 | import { Client } from '../Client';
4 |
5 | export default async function (
6 | $: Client,
7 | data: GatewayChannelPinsUpdateDispatch
8 | ): Promise {
9 | if (data.d.guild_id) {
10 | const guild = $.guilds.get(data.d.guild_id);
11 | console.log('ChannelPinsUpdate: guild check', guild?.unavailable);
12 | if (guild instanceof Guild) {
13 | const chan = guild.channels.get(data.d.channel_id);
14 | if (chan) {
15 | chan.last_pin_timestamp =
16 | data.d.last_pin_timestamp ?? chan?.last_pin_timestamp;
17 | const originalPins = chan.pins.array();
18 | await chan.pins.fetchAll();
19 | const newPins = chan.pins.array();
20 | if (newPins.length > originalPins.length) {
21 | $.emit('MessagePinned', newPins[newPins.length - 1]);
22 | } else if (newPins.length < originalPins.length) {
23 | $.emit('MessageUnpinned', originalPins[originalPins.length - 1]);
24 | }
25 | }
26 | }
27 | } else {
28 | const dm = $.directMessages.get(data.d.channel_id);
29 | if (dm) {
30 | dm.last_pin_timestamp =
31 | data.d.last_pin_timestamp ?? dm.last_pin_timestamp;
32 | const originalPins = dm.pins.array();
33 | await dm.pins.fetchAll();
34 | const newPins = dm.pins.array();
35 | if (newPins.length > originalPins.length) {
36 | $.emit('DirectMessagePinned', newPins[newPins.length - 1]);
37 | } else if (newPins.length < originalPins.length) {
38 | $.emit('DirectMessageUnpinned', originalPins[originalPins.length - 1]);
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/classes/ClientUser.ts:
--------------------------------------------------------------------------------
1 | import { BaseUser } from './BaseUser';
2 |
3 | import {
4 | APIApplication,
5 | APIUser,
6 | RESTPatchAPICurrentUserJSONBody,
7 | RESTPatchAPICurrentUserResult,
8 | } from 'discord-api-types/v8';
9 | import { Snowflake } from './Snowflake';
10 | import { Client } from '../Client';
11 |
12 | interface ClientUserApplication extends Pick {
13 | snowflake?: Snowflake;
14 | }
15 |
16 | export interface ClientUserData extends APIUser {
17 | application: ClientUserApplication;
18 | }
19 |
20 | export interface ClientUser extends ClientUserData {
21 | [key: string]: unknown;
22 | }
23 |
24 | /**
25 | * The Current User
26 | *
27 | * @export
28 | * @class ClientUser
29 | * @extends {BaseUser}
30 | */
31 | export class ClientUser extends BaseUser {
32 | constructor(protected $: Client, data: ClientUserData) {
33 | super($, data);
34 | this.application.snowflake = new Snowflake(this.application.id);
35 | }
36 |
37 | /**
38 | * Edit the ClientUser
39 | * {@link https://discord.com/developers/docs/resources/user#modify-current-user}
40 | *
41 | * ---
42 | * @param {RESTPatchAPICurrentUserJSONBody} data
43 | * @return {*} {Promise}
44 | * @memberof ClientUser
45 | */
46 | public async edit(data: RESTPatchAPICurrentUserJSONBody): Promise {
47 | try {
48 | const res = await this.$.http('PATCH', '/users/@me', {
49 | ...data,
50 | });
51 | const currentUserJSON: RESTPatchAPICurrentUserResult = await res.json();
52 | Object.assign(
53 | this,
54 | new ClientUser(this.$, {
55 | ...currentUserJSON,
56 | application: this.application,
57 | })
58 | );
59 | return this;
60 | } catch (error) {
61 | return Promise.reject(error);
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/stores/GuildBanStore.ts:
--------------------------------------------------------------------------------
1 | import {
2 | RESTGetAPIGuildBanResult,
3 | RESTGetAPIGuildBansResult,
4 | } from 'discord-api-types/v8';
5 | import { Guild } from '../classes/Guild';
6 | import { GuildBan } from '../classes/GuildBan';
7 | import { Client } from '../Client';
8 | import { BaseStore } from './BaseStore';
9 |
10 | export class GuildBanStore extends BaseStore> {
11 | constructor($: Client, protected guild: G) {
12 | super($);
13 | }
14 | /**
15 | * {@link https://discord.com/developers/docs/resources/guild#get-guild-ban}
16 | *
17 | * ---
18 | * @param {GuildBan['id']} id
19 | * @return {*} {Promise>}
20 | * @memberof GuildBanStore
21 | */
22 | async fetch(id: GuildBan['id']): Promise> {
23 | try {
24 | const res = await this.$.http(
25 | 'GET',
26 | `/guilds/${this.guild.id}/bans/${id}`
27 | );
28 | const banJSON: RESTGetAPIGuildBanResult = await res.json();
29 | const ban = new GuildBan(this.$, this.guild, banJSON);
30 | this.set(ban.id, ban);
31 | return ban;
32 | } catch (error) {
33 | return Promise.reject(error);
34 | }
35 | }
36 |
37 | /**
38 | * {@link https://discord.com/developers/docs/resources/guild#get-guild-bans}
39 | *
40 | * ---
41 | * @return {*} {Promise[]>}
42 | * @memberof GuildBanStore
43 | */
44 | async fetchAll(): Promise[]> {
45 | try {
46 | const res = await this.$.http('GET', `/guilds/${this.guild.id}/bans`);
47 | const bansJSON: RESTGetAPIGuildBansResult = await res.json();
48 | const bans = bansJSON.map(ban => new GuildBan(this.$, this.guild, ban));
49 | bans.forEach(ban => this.set(ban.id, ban));
50 | return bans;
51 | } catch (error) {
52 | return Promise.reject(error);
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/events/MESSAGE_UPDATE.ts:
--------------------------------------------------------------------------------
1 | import { Client } from '../Client';
2 | import { GatewayMessageUpdateDispatch } from 'discord-api-types/v8';
3 | import { Guild } from '../classes/Guild';
4 |
5 | export default async function (
6 | $: Client,
7 | data: GatewayMessageUpdateDispatch
8 | ): Promise {
9 | if (data.d.guild_id) {
10 | const guild = $.guilds.get(data.d.guild_id);
11 | if (guild instanceof Guild) {
12 | const channel = guild.channels.get(data.d.channel_id);
13 | if (channel) {
14 | const oldMessage = channel.messages.get(data.d.id);
15 | const newMessage = oldMessage
16 | ? Object.assign(oldMessage, data.d)
17 | : await channel.messages.fetch(data.d.id);
18 | channel.messages.set(newMessage.id, newMessage);
19 | $.emit('MessageUpdate', newMessage, oldMessage);
20 | } else {
21 | const chan = await guild.channels.fetch(data.d.channel_id);
22 | guild.channels.set(chan.id, chan);
23 | const message = await chan.messages.fetch(data.d.id);
24 | chan.messages.set(message.id, message);
25 | $.emit('MessageUpdate', message);
26 | }
27 | }
28 | } else {
29 | const channel = $.directMessages.get(data.d.channel_id);
30 | if (channel) {
31 | const oldMessage = channel.messages.get(data.d.id);
32 | const newMessage = oldMessage
33 | ? Object.assign(oldMessage, data.d)
34 | : await channel.messages.fetch(data.d.id);
35 | channel.messages.set(newMessage.id, newMessage);
36 | $.emit('DirectMessageUpdate', newMessage, oldMessage);
37 | } else {
38 | const dm = await $.directMessages.fetch(data.d.channel_id);
39 | $.directMessages.set(dm.id, dm);
40 | const message = await dm.messages.fetch(data.d.id);
41 | dm.messages.set(message.id, message);
42 | $.emit('DirectMessageUpdate', message);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "eslint:recommended",
4 | "plugin:@typescript-eslint/eslint-recommended",
5 | "plugin:@typescript-eslint/recommended",
6 | "plugin:node/recommended",
7 | "prettier"
8 | ],
9 | "parser": "@typescript-eslint/parser",
10 | "parserOptions": {
11 | "ecmaVersion": 2018,
12 | "sourceType": "module"
13 | },
14 | "plugins": ["node", "prettier", "@typescript-eslint"],
15 | "rules": {
16 | "@typescript-eslint/no-non-null-assertion": "off",
17 | "@typescript-eslint/no-use-before-define": "off",
18 | "@typescript-eslint/no-warning-comments": "off",
19 | "@typescript-eslint/no-empty-function": "off",
20 | "@typescript-eslint/explicit-function-return-type": "off",
21 | "@typescript-eslint/camelcase": "off",
22 | "node/no-missing-import": "off",
23 | "node/no-empty-function": "off",
24 | "node/no-unsupported-features/es-syntax": "off",
25 | "node/no-missing-require": "off",
26 | "node/shebang": "off",
27 | "no-dupe-class-members": "off",
28 | "require-atomic-updates": "off",
29 | "prettier/prettier": "error",
30 | "block-scoped-var": "error",
31 | "eqeqeq": "error",
32 | "no-var": "error",
33 | "prefer-const": "error",
34 | "prefer-arrow-callback": "error",
35 | "prefer-destructuring": "error",
36 | "prefer-promise-reject-errors": "error",
37 | "prefer-template": "error",
38 | "eol-last": "error",
39 | "no-trailing-spaces": "error",
40 | "quotes": ["warn", "single", { "avoidEscape": true }],
41 | "node/no-unpublished-import": [
42 | "error",
43 | {
44 | "allowModules": ["dotenv"]
45 | }
46 | ]
47 | },
48 | "overrides": [
49 | {
50 | "files": ["**/*.js"],
51 | "rules": {
52 | "@typescript-eslint/no-var-requires": "off",
53 | "node/no-unpublished-require": "off",
54 | "node/no-unpublished-import": "off"
55 | }
56 | }
57 | ]
58 | }
59 |
--------------------------------------------------------------------------------
/src/classes/MessageableChannel.ts:
--------------------------------------------------------------------------------
1 | import {
2 | APIChannel,
3 | RESTPostAPIChannelMessageJSONBody,
4 | } from 'discord-api-types/v8';
5 | import { Client } from '../Client';
6 | import { MessageStore } from '../stores/MessageStore';
7 | import { PinnedMessageStore } from '../stores/PinnedMessageStore';
8 | import { BaseChannel } from './BaseChannel';
9 | import { Message } from './Message';
10 |
11 | export type MessageableChannelData = APIChannel;
12 |
13 | export interface MessageableChannel extends BaseChannel {
14 | messages: MessageStore;
15 | pins: PinnedMessageStore;
16 | }
17 |
18 | /**
19 | * @export
20 | * @abstract
21 | * @class MessageableChannel
22 | * @extends {BaseChannel}
23 | */
24 | export abstract class MessageableChannel extends BaseChannel {
25 | messages: MessageStore;
26 | pins: PinnedMessageStore;
27 | constructor(protected $: Client, data: MessageableChannelData) {
28 | super($, data);
29 | this.messages = new MessageStore($, this);
30 | this.pins = new PinnedMessageStore($, this);
31 | this.pins.fetchAll();
32 | }
33 |
34 | /**
35 | * {@link https://discord.com/developers/docs/resources/channel#create-message}
36 | *
37 | * ---
38 | * @param {RESTPostAPIChannelMessageJSONBody} data
39 | * @return {*} {Promise>}
40 | * @memberof MessageableChannel
41 | */
42 | async send(data: RESTPostAPIChannelMessageJSONBody): Promise> {
43 | try {
44 | if (!data.content && !data.embed) {
45 | return Promise.reject(new Error('Missing content or embed.'));
46 | }
47 | const res = await this.$.http('POST', `/channels/${this.id}/messages`, {
48 | ...data,
49 | });
50 | const messageJSON = await res.json();
51 | const message = new Message(this.$, this, {
52 | ...messageJSON,
53 | });
54 | this.messages.set(message.id, message);
55 | return message;
56 | } catch (error) {
57 | return Promise.reject(error);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Main Workflow
2 |
3 | on:
4 | push:
5 | branches: [main]
6 |
7 | jobs:
8 | compile:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v2
12 | - name: Use Node
13 | uses: actions/setup-node@v2
14 | with:
15 | node-version: 15.x
16 | registry-url: 'https://registry.npmjs.org'
17 | env:
18 | NODE_AUTH_TOKEN: ${{ secrets.NPM }}
19 | - uses: pnpm/action-setup@v2.0.1
20 | with:
21 | version: 6.3.0
22 | - name: pnpm storage cache
23 | uses: actions/cache@v2
24 | with:
25 | path: ~/.pnpm-store/v3
26 | key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
27 | - name: pnpm install
28 | run: pnpm i --frozen-lockfile
29 | - name: Compile
30 | run: pnpm run precompile && pnpm run compile && pnpm run postcompile
31 | - name: Docs
32 | run: pnpm run docs
33 | - name: SemVer Increment
34 | id: semver
35 | run: echo "::set-output name=semver::$(node scripts/semver)"
36 | env:
37 | GitHubCommits: '${{ toJSON(github.event.commits) }}'
38 | - uses: EndBug/add-and-commit@v7
39 | with:
40 | add: docs
41 | default_author: github_actions
42 | message: 'docs(${{ steps.semver.outputs.semver }}): ${{ github.sha }}'
43 | signoff: true
44 | - uses: EndBug/add-and-commit@v7
45 | with:
46 | add: package.json
47 | default_author: github_actions
48 | message: 'release(${{ steps.semver.outputs.semver }}): ${{ github.sha }}'
49 | signoff: true
50 | - name: Publish to NPM
51 | run: pnpm publish
52 | - name: GitHub Release
53 | uses: softprops/action-gh-release@v1
54 | with:
55 | tag_name: ${{ steps.semver.outputs.semver }}
56 | body: 'https://www.npmjs.com/package/esmcord/v/${{ steps.semver.outputs.semver }}'
57 | env:
58 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
59 |
--------------------------------------------------------------------------------
/src/stores/ChannelStore.ts:
--------------------------------------------------------------------------------
1 | import {
2 | RESTGetAPIChannelResult,
3 | RESTPostAPIGuildChannelJSONBody,
4 | RESTPostAPIGuildChannelResult,
5 | } from 'discord-api-types/v8';
6 | import { Guild } from '../classes/Guild';
7 | import { GuildText } from '../classes/GuildText';
8 | import { Client } from '../Client';
9 | import { BaseStore } from './BaseStore';
10 |
11 | export class ChannelStore extends BaseStore {
12 | constructor($: Client, protected guild: Guild) {
13 | super($);
14 | }
15 |
16 | /**
17 | * {@link https://discord.com/developers/docs/resources/channel#get-channel}
18 | *
19 | * ---
20 | * @param {GuildText['id']} id
21 | * @return {*} {Promise}
22 | * @memberof ChannelStore
23 | */
24 | async fetch(id: GuildText['id']): Promise {
25 | try {
26 | const res = await this.$.http('GET', `/channels/${id}`);
27 | const channelJSON: RESTGetAPIChannelResult = await res.json();
28 | const channel = new GuildText(this.$, await this.guild, {
29 | ...channelJSON,
30 | owner_id: undefined,
31 | });
32 | this.set(channel.id, channel);
33 | return channel;
34 | } catch (error) {
35 | return Promise.reject(error);
36 | }
37 | }
38 |
39 | /**
40 | * {@link https://discord.com/developers/docs/resources/guild#create-guild-channel}
41 | *
42 | * ---
43 | * @param {RESTPostAPIGuildChannelJSONBody} data
44 | * @return {*} {Promise}
45 | * @memberof ChannelStore
46 | */
47 | async create(data: RESTPostAPIGuildChannelJSONBody): Promise {
48 | try {
49 | const res = await this.$.http(
50 | 'POST',
51 | `/guilds/${this.guild.id}/channels`,
52 | data
53 | );
54 | const channelJSON: RESTPostAPIGuildChannelResult = await res.json();
55 | const channel = new GuildText(this.$, await this.guild, {
56 | ...channelJSON,
57 | owner_id: undefined,
58 | });
59 | this.set(channel.id, channel);
60 | return channel;
61 | } catch (error) {
62 | return Promise.reject(error);
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/ItsRauf/esmcord/issues)
2 | [](https://github.com/ItsRauf/esmcord/network)
3 | [](https://github.com/ItsRauf/esmcord/stargazers)
4 | [](https://github.com/ItsRauf/esmcord/blob/main/LICENSE)
5 | 
6 |
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ESMCord
18 |
19 |
20 |
21 |
22 | Discord library written in Typescript leveraging the latest ECMAScript features.
23 |
24 |
25 | Documentation
26 | •
27 | Report a Bug
28 | •
29 | Request a Feature
30 |
31 |
32 |
33 |
34 | ## Example Usage
35 |
36 | ```js
37 | import { Client } from 'esmcord';
38 |
39 | const esmcord = new Client(process.env.TOKEN, {
40 | debug: false,
41 | });
42 |
43 | esmcord.on('Ready', time => {
44 | console.log(`Ready at ${time}`);
45 | });
46 |
47 | esmcord.connect();
48 | ```
49 |
50 | ## Contributing
51 |
52 | Contributions are what make the open source community such a fantastic place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
53 |
54 | 1. Fork the Project
55 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
56 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
57 | 4. Push to the Branch (`git push origin feature/AmazingFeature`)
58 | 5. Open a Pull Request
59 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # TernJS port file
104 | .tern-port
105 |
106 | example
107 | build
108 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "esmcord",
3 | "version": "0.3.5",
4 | "description": "Discord library written in Typescript leveraging the latest ECMAScript features.",
5 | "keywords": [
6 | "discord",
7 | "typescript",
8 | "ecmascript",
9 | "discord.js"
10 | ],
11 | "main": "./build/mod.js",
12 | "type": "module",
13 | "files": [
14 | "build/*",
15 | "docs/*",
16 | ".eslintrc",
17 | ".prettierrc",
18 | ".swcrc",
19 | ".gitignore",
20 | "tsconfig.json"
21 | ],
22 | "scripts": {
23 | "precompile": "pnpm run lint",
24 | "compile": "swc src -d build",
25 | "postcompile": "node scripts/d.ts",
26 | "semver": "node scripts/semver",
27 | "docs": "typedoc --out docs src",
28 | "lint": "prettier --check \"src/**/*.ts\"",
29 | "postlint": "eslint src --ext .ts",
30 | "lint:fix": "prettier --write \"src/**/*.ts\"",
31 | "postlint:fix": "eslint src --ext .ts --fix",
32 | "start:example": "node --unhandled-rejections=strict --trace-warnings --trace-uncaught --experimental-specifier-resolution=node example/mod.js"
33 | },
34 | "author": "Rauf",
35 | "license": "GPL-3.0",
36 | "repository": {
37 | "type": "git",
38 | "url": "git+https://github.com/ItsRauf/esmcord.git"
39 | },
40 | "types": "./build/mod.d.ts",
41 | "devDependencies": {
42 | "@swc/cli": "^0.1.45",
43 | "@swc/core": "^1.2.58",
44 | "@types/node": "^14.17.1",
45 | "@typescript-eslint/eslint-plugin": "^4.25.0",
46 | "@typescript-eslint/parser": "^4.25.0",
47 | "dotenv": "^8.6.0",
48 | "esdoc": "^1.1.0",
49 | "esdoc-ecmascript-proposal-plugin": "^1.0.0",
50 | "esdoc-standard-plugin": "^1.0.0",
51 | "eslint": "^7.27.0",
52 | "eslint-config-prettier": "^7.2.0",
53 | "eslint-plugin-node": "^11.1.0",
54 | "eslint-plugin-prettier": "^3.4.0",
55 | "fast-glob": "^3.2.5",
56 | "prettier": "^2.3.0",
57 | "semver": "^7.3.5",
58 | "typedoc": "^0.20.36",
59 | "typescript": "4.2.4"
60 | },
61 | "engines": {
62 | "node": ">=12.2.0"
63 | },
64 | "dependencies": {
65 | "@swc/helpers": "^0.2.12",
66 | "@types/centra": "^2.2.0",
67 | "@types/module-alias": "^2.0.0",
68 | "@types/ws": "^7.4.4",
69 | "ansi-colors": "^4.1.1",
70 | "centra": "^2.4.2",
71 | "discord-api-types": "^0.12.1",
72 | "module-alias": "^2.2.2",
73 | "reflect-metadata": "^0.1.13",
74 | "ts-node": "^9.1.1",
75 | "ws": "^7.4.6"
76 | }
77 | }
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: 'CodeQL'
13 |
14 | on:
15 | push:
16 | branches: [devel]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [main]
20 | schedule:
21 | - cron: '0 * * * *'
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 | permissions:
28 | actions: read
29 | contents: read
30 | security-events: write
31 |
32 | strategy:
33 | fail-fast: false
34 | matrix:
35 | language: ['typescript']
36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
37 | # Learn more:
38 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
39 |
40 | steps:
41 | - name: Checkout repository
42 | uses: actions/checkout@v2
43 |
44 | # Initializes the CodeQL tools for scanning.
45 | - name: Initialize CodeQL
46 | uses: github/codeql-action/init@v1
47 | with:
48 | languages: ${{ matrix.language }}
49 | # If you wish to specify custom queries, you can do so here or in a config file.
50 | # By default, queries listed here will override any specified in a config file.
51 | # Prefix the list here with "+" to use these queries and those in the config file.
52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
53 |
54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
55 | # If this step fails, then you should remove it and run the build manually (see below)
56 | - name: Autobuild
57 | uses: github/codeql-action/autobuild@v1
58 |
59 | # ℹ️ Command-line programs to run using the OS shell.
60 | # 📚 https://git.io/JvXDl
61 |
62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
63 | # and modify them (or add more) to build your code if your project
64 | # uses a compiled language
65 |
66 | #- run: |
67 | # make bootstrap
68 | # make release
69 |
70 | - name: Perform CodeQL Analysis
71 | uses: github/codeql-action/analyze@v1
72 |
--------------------------------------------------------------------------------
/src/classes/GuildMember.ts:
--------------------------------------------------------------------------------
1 | import {
2 | APIGuildMember,
3 | RESTPatchAPIGuildMemberJSONBody,
4 | RESTPatchAPIGuildMemberResult,
5 | RESTPutAPIGuildBanJSONBody,
6 | } from 'discord-api-types/v8';
7 | import { Client } from '../Client';
8 | import { Base } from './Base';
9 | import { Guild } from './Guild';
10 | import { GuildBan } from './GuildBan';
11 | import { User } from './User';
12 |
13 | interface APIGuildMemberWithOptionalDeafAndMute
14 | extends Omit {
15 | deaf?: APIGuildMember['deaf'];
16 | mute?: APIGuildMember['mute'];
17 | }
18 |
19 | export interface GuildMember
20 | extends Omit {
21 | id: `${bigint}`;
22 | guild: G;
23 | user: User;
24 | }
25 | export class GuildMember<
26 | G extends Guild
27 | > extends Base {
28 | constructor(
29 | $: Client,
30 | public guild: G,
31 | data: APIGuildMemberWithOptionalDeafAndMute
32 | ) {
33 | super($, data);
34 | this.user = new User($, data.user!);
35 | this.id = this.user.id;
36 | }
37 |
38 | async edit(data: RESTPatchAPIGuildMemberJSONBody): Promise {
39 | try {
40 | const res = await this.$.http(
41 | 'PATCH',
42 | `/guilds/${this.guild.id}/members/${this.user.id}`,
43 | {
44 | ...data,
45 | }
46 | );
47 | const GuildMemberJSON: RESTPatchAPIGuildMemberResult = await res.json();
48 | Object.assign(this, new GuildMember(this.$, this.guild, GuildMemberJSON));
49 | return this;
50 | } catch (error) {
51 | return Promise.reject(error);
52 | }
53 | }
54 |
55 | /**
56 | * {@link https://discord.com/developers/docs/resources/guild#create-guild-ban}
57 | *
58 | * ---
59 | * @param {RESTPutAPIGuildBanJSONBody} data
60 | * @return {*} {Promise>}
61 | * @memberof GuildMember
62 | */
63 | async ban(data: RESTPutAPIGuildBanJSONBody): Promise> {
64 | try {
65 | await this.$.http(
66 | 'PUT',
67 | `/guilds/${this.guild.id}/bans/${this.user.id}`,
68 | { ...data }
69 | );
70 | const ban = new GuildBan(this.$, this.guild, {
71 | user: this.user,
72 | reason: data.reason ?? '',
73 | });
74 | this.guild.bans.set(ban.id, ban);
75 | return ban;
76 | } catch (error) {
77 | return Promise.reject(error);
78 | }
79 | }
80 |
81 | /**
82 | * {@link https://discord.com/developers/docs/resources/guild#remove-guild-member}
83 | *
84 | * ---
85 | * @return {*} {Promise}
86 | * @memberof GuildMember
87 | */
88 | async kick(): Promise {
89 | try {
90 | await this.$.http(
91 | 'DELETE',
92 | `/guilds/${this.guild.id}/members/${this.id}`
93 | );
94 | } catch (error) {
95 | return Promise.reject(error);
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/stores/GuildMemberStore.ts:
--------------------------------------------------------------------------------
1 | import {
2 | RESTGetAPIGuildMemberResult,
3 | RESTGetAPIGuildMembersQuery,
4 | RESTGetAPIGuildMembersResult,
5 | RESTGetAPIGuildMembersSearchQuery,
6 | RESTGetAPIGuildMembersSearchResult,
7 | } from 'discord-api-types/v8';
8 | import { Guild } from '../classes/Guild';
9 | import { GuildMember } from '../classes/GuildMember';
10 | import { Client } from '../Client';
11 | import { BaseStore } from './BaseStore';
12 |
13 | export class GuildMemberStore extends BaseStore<
14 | GuildMember
15 | > {
16 | constructor($: Client, protected guild: G) {
17 | super($);
18 | }
19 |
20 | /**
21 | * {@link https://discord.com/developers/docs/resources/guild#list-guild-members}
22 | *
23 | * ---
24 | * @param {GuildMember['id']} id
25 | * @return {*} {Promise>}
26 | * @memberof GuildMemberStore
27 | */
28 | async fetch(id: GuildMember['id']): Promise> {
29 | try {
30 | const res = await this.$.http(
31 | 'GET',
32 | `/guilds/${this.guild.id}/members/${id}`
33 | );
34 | const guildMemberJSON: RESTGetAPIGuildMemberResult = await res.json();
35 | const guildMember = new GuildMember(this.$, this.guild, guildMemberJSON);
36 | this.set(guildMember.id, guildMember);
37 | return guildMember;
38 | } catch (error) {
39 | return Promise.reject(error);
40 | }
41 | }
42 |
43 | /**
44 | * {@link https://discord.com/developers/docs/resources/guild#list-guild-members}
45 | *
46 | * ---
47 | * @param {RESTGetAPIGuildMembersQuery} query
48 | * @return {*} {Promise[]>}
49 | * @memberof GuildMemberStore
50 | */
51 | async fetchAll(
52 | query: RESTGetAPIGuildMembersQuery
53 | ): Promise[]> {
54 | try {
55 | const res = await this.$.http(
56 | 'GET',
57 | `/guilds/${this.guild.id}/members`,
58 | undefined,
59 | { ...query }
60 | );
61 | const guildMembersJSON: RESTGetAPIGuildMembersResult = await res.json();
62 | const guildMembers = guildMembersJSON.map(
63 | gm => new GuildMember(this.$, this.guild, gm)
64 | );
65 | guildMembers.forEach(gm => this.set(gm.id, gm));
66 | return guildMembers;
67 | } catch (error) {
68 | return Promise.reject(error);
69 | }
70 | }
71 |
72 | /**
73 | *{@link https://discord.com/developers/docs/resources/guild#search-guild-members}
74 | *
75 | * ---
76 | * @param {RESTGetAPIGuildMembersSearchQuery} query
77 | * @return {*} {Promise[]>}
78 | * @memberof GuildMemberStore
79 | */
80 | async search(
81 | query: RESTGetAPIGuildMembersSearchQuery
82 | ): Promise[]> {
83 | try {
84 | const res = await this.$.http(
85 | 'GET',
86 | `/guilds/${this.guild.id}/members/search`,
87 | undefined,
88 | { ...query }
89 | );
90 | const guildMemberSearchResultsJSON: RESTGetAPIGuildMembersSearchResult =
91 | await res.json();
92 | const guildMembers = guildMemberSearchResultsJSON.map(
93 | gm => new GuildMember(this.$, this.guild, gm)
94 | );
95 | guildMembers.forEach(gm => this.set(gm.id, gm));
96 | return guildMembers;
97 | } catch (error) {
98 | return Promise.reject(error);
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/classes/Message.ts:
--------------------------------------------------------------------------------
1 | import {
2 | APIMessage,
3 | RESTPostAPIChannelMessageCrosspostResult,
4 | RESTPostAPIChannelMessageJSONBody,
5 | RESTPostAPIChannelMessageResult,
6 | } from 'discord-api-types/v8';
7 | import { Client } from '../Client';
8 | import { Base } from './Base';
9 | import { Guild } from './Guild';
10 | import { MessageableChannel } from './MessageableChannel';
11 | import { User } from './User';
12 |
13 | export interface Message extends APIMessage {
14 | author: User;
15 | channel: C;
16 | guild?: Guild;
17 | }
18 |
19 | /**
20 | * {@link https://discord.com/developers/docs/resources/channel#message-object}
21 | *
22 | * ---
23 | * @export
24 | * @class Message
25 | * @extends {Base}
26 | * @template C {MessageableChannel}
27 | */
28 | export class Message extends Base {
29 | constructor(protected $: Client, public channel: C, data: APIMessage) {
30 | super($, data);
31 | this.author = new User($, {
32 | ...data.author,
33 | });
34 | if (data.guild_id) {
35 | this.guild = $.guilds.get(data.guild_id) as Guild | undefined;
36 | }
37 | }
38 |
39 | /**
40 | * Check if the current user can edit the current Message
41 | *
42 | * @readonly
43 | * @type {boolean}
44 | * @memberof Message
45 | */
46 | get editable(): boolean {
47 | if (this.author.id === this.$.user.id) return true;
48 | return false;
49 | }
50 |
51 | /**
52 | * Edits the current Message
53 | * {@link https://discord.com/developers/docs/resources/channel#edit-message}
54 | *
55 | * ---
56 | * @param {RESTPostAPIChannelMessageJSONBody} data
57 | * @return {*} {Promise}
58 | * @memberof Message
59 | */
60 | async edit(data: RESTPostAPIChannelMessageJSONBody): Promise {
61 | if (!this.editable) return Promise.reject(new Error());
62 | try {
63 | const res = await this.$.http(
64 | 'POST',
65 | `/channels/${this.channel_id}/messages/${this.id}`,
66 | {
67 | ...data,
68 | }
69 | );
70 | const messageJSON: RESTPostAPIChannelMessageResult = await res.json();
71 | Object.assign(this, new Message(this.$, this.channel, messageJSON));
72 | return this;
73 | } catch (error) {
74 | return Promise.reject(error);
75 | }
76 | }
77 |
78 | /**
79 | * Crossposts the current message
80 | * {@link https://discord.com/developers/docs/resources/channel#crosspost-message}
81 | *
82 | * ---
83 | * @return {*} {Promise}
84 | * @memberof Message
85 | */
86 | async crosspost(): Promise {
87 | try {
88 | const res = await this.$.http(
89 | 'POST',
90 | `/channels/${this.channel_id}/messages/${this.id}/crosspost`
91 | );
92 | const messageJSON: RESTPostAPIChannelMessageCrosspostResult =
93 | await res.json();
94 | Object.assign(this, new Message(this.$, this.channel, messageJSON));
95 | } catch (error) {
96 | return Promise.reject(error);
97 | }
98 | }
99 |
100 | /**
101 | * Deletes the current message
102 | * {@link https://discord.com/developers/docs/resources/channel#delete-message}
103 | *
104 | * ---
105 | * @return {*} {Promise}
106 | * @memberof Message
107 | */
108 | async delete(): Promise {
109 | try {
110 | await this.$.http(
111 | 'DELETE',
112 | `/channels/${this.channel_id}/messages/${this.id}`
113 | );
114 | return this.channel.messages.delete(this.id);
115 | } catch (error) {
116 | return Promise.reject(error);
117 | }
118 | }
119 |
120 | /**
121 | * {@link https://discord.com/developers/docs/resources/channel#pin-message}
122 | *
123 | * ---
124 | * @return {*} {Promise}
125 | * @memberof Message
126 | */
127 | async pin(): Promise {
128 | try {
129 | await this.$.http('PUT', `/channels/${this.channel_id}/pins/${this.id}`);
130 | this.channel.pins.set(this.id, this);
131 | } catch (error) {
132 | return Promise.reject(error);
133 | }
134 | }
135 |
136 | async unpin(): Promise {
137 | try {
138 | await this.$.http(
139 | 'DELETE',
140 | `/channels/${this.channel_id}/pins/${this.id}`
141 | );
142 | this.channel.pins.delete(this.id);
143 | } catch (error) {
144 | return Promise.reject(error);
145 | }
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/docs/modules/intents.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Intents | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module Intents
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | Index
70 |
71 |
72 |
73 | Enumerations
74 |
77 |
78 |
79 |
80 |
81 |
82 |
101 |
102 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/classes_user.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | classes/User | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module classes/User
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/classes_guild.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | classes/Guild | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module classes/Guild
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/helpers_logger.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | helpers/Logger | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module helpers/Logger
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/classes_base.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | classes/Base | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module classes/Base
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/classes_dmchannel.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | classes/DMChannel | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module classes/DMChannel
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/classes_baseuser.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | classes/BaseUser | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module classes/BaseUser
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/classes_snowflake.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | classes/Snowflake | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module classes/Snowflake
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/classes_message.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | classes/Message | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module classes/Message
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/stores_guildstore.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | stores/GuildStore | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module stores/GuildStore
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/classes_basechannel.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | classes/BaseChannel | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module classes/BaseChannel
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/classes_guildban.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | classes/GuildBan | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module classes/GuildBan
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/stores_channelstore.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | stores/ChannelStore | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module stores/ChannelStore
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/stores_basestore.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | stores/BaseStore | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module stores/BaseStore
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/classes_guildmember.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | classes/GuildMember | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module classes/GuildMember
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/stores_messagestore.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | stores/MessageStore | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module stores/MessageStore
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/classes_unavailableguild.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | classes/UnavailableGuild | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module classes/UnavailableGuild
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/stores_guildbanstore.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | stores/GuildBanStore | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module stores/GuildBanStore
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/stores_directmessagestore.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | stores/DirectMessageStore | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module stores/DirectMessageStore
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/stores_guildmemberstore.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | stores/GuildMemberStore | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module stores/GuildMemberStore
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/stores_pinnedmessagestore.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | stores/PinnedMessageStore | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module stores/PinnedMessageStore
62 |
63 |
64 |
65 |
103 |
124 |
125 |
Generated using TypeDoc
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/modules/classes_guildtext.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | classes/GuildText | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module classes/GuildText
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | Index
70 |
71 |
72 |
78 |
79 | Interfaces
80 |
83 |
84 |
85 |
86 |
87 |
88 |
110 |
111 |
112 |
133 |
134 |
Generated using TypeDoc
135 |
136 |
137 |
138 |
139 |
--------------------------------------------------------------------------------
/docs/modules/classes_clientuser.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | classes/ClientUser | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module classes/ClientUser
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | Index
70 |
71 |
72 |
78 |
79 | Interfaces
80 |
83 |
84 |
85 |
86 |
87 |
88 |
110 |
111 |
112 |
133 |
134 |
Generated using TypeDoc
135 |
136 |
137 |
138 |
139 |
--------------------------------------------------------------------------------
/docs/modules/client.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Client | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module Client
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | Index
70 |
71 |
72 |
78 |
79 | Interfaces
80 |
84 |
85 |
86 |
87 |
88 |
89 |
114 |
115 |
116 |
137 |
138 |
Generated using TypeDoc
139 |
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/docs/modules/classes_messageablechannel.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | classes/MessageableChannel | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module classes/MessageableChannel
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | Index
70 |
71 |
72 |
78 |
79 | Type aliases
80 |
83 |
84 |
85 |
86 |
87 |
88 | Type aliases
89 |
90 |
91 | MessageableChannelData
92 | MessageableChannelData: APIChannel
93 |
98 |
99 |
100 |
101 |
123 |
124 |
125 |
146 |
147 |
Generated using TypeDoc
148 |
149 |
150 |
151 |
152 |
--------------------------------------------------------------------------------
/docs/modules/events_ready.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | events/READY | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module events/READY
62 |
63 |
64 |
65 |
66 |
67 |
68 |
81 |
82 | Functions
83 |
84 |
85 | default
86 |
87 | - default($: Client, data: GatewayReadyDispatch): void
88 |
89 |
90 | -
91 |
96 |
Parameters
97 |
98 | -
99 |
100 |
101 | -
102 |
data: GatewayReadyDispatch
103 |
104 |
105 | Returns void
106 |
107 |
108 |
109 |
110 |
111 |
130 |
131 |
132 |
153 |
154 |
Generated using TypeDoc
155 |
156 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/docs/modules/events_guild_create.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | events/GUILD_CREATE | esmcord
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | - Preparing search index...
24 | - The search index is not available
25 |
26 |
esmcord
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |
Module events/GUILD_CREATE
62 |
63 |
64 |
65 |
66 |
67 |
68 |
81 |
82 | Functions
83 |
84 |
85 | default
86 |
87 | - default($: Client, data: GatewayGuildCreateDispatch): void
88 |
89 |
90 | -
91 |
96 |
Parameters
97 |
98 | -
99 |
100 |
101 | -
102 |
data: GatewayGuildCreateDispatch
103 |
104 |
105 | Returns void
106 |
107 |
108 |
109 |
110 |
111 |
130 |
131 |
132 |
153 |
154 |
Generated using TypeDoc
155 |
156 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/src/classes/Guild.ts:
--------------------------------------------------------------------------------
1 | import {
2 | APIGuild,
3 | RESTGetAPIGuildPreviewResult,
4 | RESTGetAPIGuildPruneCountQuery,
5 | RESTGetAPIGuildPruneCountResult,
6 | RESTPatchAPIGuildJSONBody,
7 | RESTPatchAPIGuildResult,
8 | RESTPostAPIGuildPruneJSONBody,
9 | RESTPostAPIGuildPruneResult,
10 | RESTPutAPIGuildBanJSONBody,
11 | } from 'discord-api-types/v8';
12 | import { Client } from '../Client';
13 | import { Base } from './Base';
14 | import { Snowflake } from './Snowflake';
15 | import { ChannelStore } from '../stores/ChannelStore';
16 | import { GuildText } from './GuildText';
17 | import { GuildBanStore } from '../stores/GuildBanStore';
18 | import { GuildMemberStore } from '../stores/GuildMemberStore';
19 | import { GuildMember } from './GuildMember';
20 | import { User } from './User';
21 | import { GuildBan } from './GuildBan';
22 |
23 | export interface Guild extends Omit {
24 | channels: ChannelStore;
25 | members: GuildMemberStore;
26 | bans: GuildBanStore;
27 | }
28 | /**
29 | * {@link https://discord.com/developers/docs/resources/guild#guild-object}
30 | *
31 | * ---
32 | * @export
33 | * @class Guild
34 | * @extends {Base}
35 | */
36 | export class Guild extends Base {
37 | [key: string]: unknown;
38 | public snowflake: Snowflake;
39 | // deletable!: boolean;
40 |
41 | constructor(protected $: Client, data: APIGuild) {
42 | super($, data);
43 | this.snowflake = new Snowflake(this.id);
44 | this.bans = new GuildBanStore($, this);
45 | this.channels = new ChannelStore($, this);
46 | data.channels?.forEach(channel =>
47 | this.channels.set(
48 | channel.id,
49 | new GuildText($, this, {
50 | ...channel,
51 | owner_id: undefined,
52 | })
53 | )
54 | );
55 | this.members = new GuildMemberStore($, this);
56 | data.members?.forEach(member => {
57 | this.members.set(member.user!.id, new GuildMember($, this, member));
58 | });
59 | }
60 |
61 | /**
62 | * Modify the current guild
63 | * {@link https://discord.com/developers/docs/resources/guild#modify-guild}
64 | *
65 | * ---
66 | * @param {RESTPatchAPIGuildJSONBody} data
67 | * @return {*} {Promise}
68 | * @memberof Guild
69 | */
70 | async edit(data: RESTPatchAPIGuildJSONBody): Promise {
71 | try {
72 | const res = await this.$.http('PATCH', `/guilds/${this.id}`, {
73 | ...data,
74 | });
75 | const guildJSON: RESTPatchAPIGuildResult = await res.json();
76 | Object.assign(this, new Guild(this.$, guildJSON));
77 | return this;
78 | } catch (error) {
79 | return Promise.reject(error);
80 | }
81 | }
82 |
83 | /**
84 | * Check if the current guild is deleteable
85 | *
86 | * @readonly
87 | * @type {boolean}
88 | * @memberof Guild
89 | */
90 | get deletable(): boolean {
91 | return this.owner_id === this.$.user.id;
92 | }
93 |
94 | /**
95 | * Delete the current guild
96 | * {@link https://discord.com/developers/docs/resources/guild#delete-guild}
97 | *
98 | * ---
99 | * @return {*} {Promise}
100 | * @memberof Guild
101 | */
102 | async delete(): Promise {
103 | if (this.deletable) {
104 | await this.$.http('DELETE', `/guilds/${this.id}`);
105 | } else {
106 | return Promise.reject(new Error('User is not owner of this guild'));
107 | }
108 | }
109 |
110 | /**
111 | * {@link https://discord.com/developers/docs/resources/guild#create-guild-ban}
112 | *
113 | * ---
114 | * @param {User['id']} id
115 | * @param {RESTPutAPIGuildBanJSONBody} data
116 | * @return {*} {Promise>}
117 | * @memberof Guild
118 | */
119 | async forceban(
120 | id: User['id'],
121 | data: RESTPutAPIGuildBanJSONBody
122 | ): Promise> {
123 | try {
124 | await this.$.http('PUT', `/guilds/${this.id}/bans/${id}`, { ...data });
125 | const ban = new GuildBan(this.$, this, {
126 | reason: data.reason ?? '',
127 | });
128 | return ban;
129 | } catch (error) {
130 | return Promise.reject(error);
131 | }
132 | }
133 |
134 | /**
135 | * {@link https://discord.com/developers/docs/resources/guild#remove-guild-ban}
136 | *
137 | * ---
138 | * @param {User['id']} id
139 | * @return {*} {Promise}
140 | * @memberof Guild
141 | */
142 | async unban(id: User['id']): Promise {
143 | try {
144 | await this.$.http('DELETE', `/guilds/${this.id}/bans/${id}`);
145 | this.bans.delete(id);
146 | } catch (error) {
147 | return Promise.reject(error);
148 | }
149 | }
150 |
151 | /**
152 | * {@link https://discord.com/developers/docs/resources/guild#get-guild-preview}
153 | *
154 | * ---
155 | * @return {*} {Promise}
156 | * @memberof Guild
157 | */
158 | async getPreview(): Promise {
159 | try {
160 | const res = await this.$.http('GET', `/guilds/${this.id}/preview`);
161 | const guildPreview: RESTGetAPIGuildPreviewResult = await res.json();
162 | return guildPreview;
163 | } catch (error) {
164 | return Promise.reject(error);
165 | }
166 | }
167 |
168 | /**
169 | * {@link https://discord.com/developers/docs/resources/guild#get-guild-prune-count}
170 | *
171 | * ---
172 | * @param {RESTGetAPIGuildPruneCountQuery} [query]
173 | * @return {*} {Promise}
174 | * @memberof Guild
175 | */
176 | async getPruneCount(
177 | query?: RESTGetAPIGuildPruneCountQuery
178 | ): Promise {
179 | try {
180 | const res = await this.$.http(
181 | 'GET',
182 | `/guilds/${this.id}/prune`,
183 | undefined,
184 | query ? { ...query } : {}
185 | );
186 | const guildPruneCount: RESTGetAPIGuildPruneCountResult = await res.json();
187 | return guildPruneCount;
188 | } catch (error) {
189 | return Promise.reject(error);
190 | }
191 | }
192 |
193 | /**
194 | * {@link https://discord.com/developers/docs/resources/guild#begin-guild-prune}
195 | *
196 | * ---
197 | * @param {RESTPostAPIGuildPruneJSONBody} [data]
198 | * @return {*} {Promise}
199 | * @memberof Guild
200 | */
201 | async prune(
202 | data?: RESTPostAPIGuildPruneJSONBody
203 | ): Promise {
204 | try {
205 | const res = await this.$.http(
206 | 'GET',
207 | `/guilds/${this.id}/prune`,
208 | data ? { ...data } : {}
209 | );
210 | const guildPrune: RESTPostAPIGuildPruneResult = await res.json();
211 | return guildPrune;
212 | } catch (error) {
213 | return Promise.reject(error);
214 | }
215 | }
216 | }
217 |
--------------------------------------------------------------------------------