├── package ├── .npmignore ├── package.json ├── LICENSE └── README.md ├── src ├── actions │ ├── stickerpacks.ts │ ├── dm.ts │ ├── gateway.ts │ ├── welcomescreen.ts │ ├── ban.ts │ ├── voice.ts │ ├── reaction.ts │ ├── widget.ts │ ├── sticker.ts │ ├── emoji.ts │ ├── invite.ts │ ├── stageinstance.ts │ ├── role.ts │ ├── template.ts │ ├── groupdm.ts │ ├── oauth2.ts │ ├── user.ts │ ├── member.ts │ ├── _common.ts │ ├── scheduledevent.ts │ ├── message.ts │ ├── thread.ts │ ├── webhook.ts │ ├── channel.ts │ ├── guild.ts │ └── application.ts ├── index.ts ├── authorization.ts ├── actions.ts ├── _common.ts ├── request.ts ├── voice.ts ├── tools.ts ├── events.ts ├── client.ts ├── helpers.ts └── types.ts ├── package.json ├── tsconfig.json ├── README.md ├── LICENSE └── .gitignore /package/.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | !dist/**/* 3 | dist/**/_* 4 | -------------------------------------------------------------------------------- /src/actions/stickerpacks.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as types from '../types'; 4 | 5 | export const ListNitro = (requestOptions?: RequestOptions) => 6 | Request<{ sticker_packs: types.StickerPack[]; }>(METHODS.GET, PATHS.sticker_packs, requestOptions); 7 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { Client, ClientEvents } from './client'; 2 | export { Authorization } from './authorization'; 3 | export { Events } from './events'; 4 | export * as Actions from './actions'; 5 | export * as Helpers from './helpers'; 6 | import type * as Types from './types'; export type { Types }; 7 | export * as Tools from './tools'; 8 | export { Voice, VoiceEvents } from './voice'; 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "build": "esbuild 'src/index.ts' --outdir='package/dist' --external:ws --bundle --platform=node --format=esm --analyze", 4 | "postbuild": "tsc" 5 | }, 6 | "devDependencies": { 7 | "@types/node": "*", 8 | "@types/ws": "8.5", 9 | "esbuild": "0.14", 10 | "typescript": "4.7" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/actions/dm.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as types from '../types'; 4 | 5 | export const Create = (params: { 6 | recipient_id: string; 7 | }, requestOptions?: RequestOptions) => 8 | Request(METHODS.POST, Path(PATHS.users, PATHS.me, PATHS.channels), requestOptions, params); 9 | 10 | export const Close = (channel_id: string, requestOptions?: RequestOptions) => 11 | Request(METHODS.DELETE, Path(PATHS.channels, channel_id), requestOptions); 12 | -------------------------------------------------------------------------------- /src/actions/gateway.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as types from '../types'; 4 | 5 | export const Get = (requestOptions?: RequestOptions) => 6 | Request<{ 7 | url: string; 8 | }>(METHODS.GET, PATHS.gateway, requestOptions); 9 | 10 | export const GetBot = (requestOptions?: RequestOptions) => 11 | Request<{ 12 | url: string; 13 | shards: number; 14 | session_start_limit: types.SessionStartLimit; 15 | }>(METHODS.GET, Path(PATHS.gateway, PATHS.bot), requestOptions); 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "ES2020", 4 | "target": "ES2020", 5 | "strict": true, 6 | "moduleResolution": "node", 7 | "outDir": "package/dist", 8 | "declaration": true, 9 | "emitDeclarationOnly": true, 10 | "stripInternal": true, 11 | "skipLibCheck": true, 12 | "isolatedModules": true, 13 | "removeComments": true, 14 | "noUncheckedIndexedAccess": true, 15 | "noPropertyAccessFromIndexSignature": true, 16 | "lib": [] 17 | }, 18 | "include": [ 19 | "src/index.ts" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "discord-slim", 3 | "version": "2.7.0", 4 | "description": "Lightweight Discord API library for Node.js.", 5 | "author": "Hanabishi", 6 | "license": "MIT", 7 | "repository": "github:HanabishiRecca/Discord-Slim", 8 | "keywords": [ 9 | "discord", 10 | "bot", 11 | "api", 12 | "client", 13 | "library", 14 | "framework" 15 | ], 16 | "type": "module", 17 | "main": "dist/index.js", 18 | "types": "dist/index.d.ts", 19 | "sideEffects": false, 20 | "engines": { 21 | "node": ">=14" 22 | }, 23 | "dependencies": { 24 | "ws": "8.7" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DISCONTINUATION NOTICE 2 | The project is discontinued and will not be maintained further. 3 | I don't use Discord anymore and don't want to work with it. Sorry. 4 | 5 | # Discord Slim 6 | [![npm](https://img.shields.io/npm/v/discord-slim?style=for-the-badge&logo=npm)](https://www.npmjs.com/package/discord-slim) 7 | 8 | Lightweight **Discord API** library for **Node.js**. 9 | Provides pure API interaction via type definitions and some helper tools, without excessive abstractions. 10 | 11 | NPM: [discord-slim](https://www.npmjs.com/package/discord-slim). 12 | Usage info: see [package](./package) readme. 13 | 14 | ## Build the package from source 15 | ```sh 16 | npm i 17 | npm run build 18 | ``` 19 | -------------------------------------------------------------------------------- /src/actions/welcomescreen.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as types from '../types'; 4 | 5 | export const Get = (guild_id: string, requestOptions?: RequestOptions) => 6 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.welcome_screen), requestOptions); 7 | 8 | export const Modify = (guild_id: string, params: { 9 | enabled?: boolean | null; 10 | welcome_channels?: types.WelcomeScreenChannel[] | null; 11 | description?: string | null; 12 | }, requestOptions?: RequestOptions) => 13 | Request(METHODS.PATCH, Path(PATHS.guilds, guild_id, PATHS.welcome_screen), requestOptions, params); 14 | -------------------------------------------------------------------------------- /src/actions/ban.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as types from '../types'; 4 | 5 | export const Get = (guild_id: string, user_id: string, requestOptions?: RequestOptions) => 6 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.bans, user_id), requestOptions); 7 | 8 | export const Add = (guild_id: string, user_id: string, params?: { 9 | delete_message_days?: number; 10 | }, requestOptions?: RequestOptions) => 11 | Request(METHODS.PUT, Path(PATHS.guilds, guild_id, PATHS.bans, user_id), requestOptions, params); 12 | 13 | export const Remove = (guild_id: string, user_id: string, requestOptions?: RequestOptions) => 14 | Request(METHODS.DELETE, Path(PATHS.guilds, guild_id, PATHS.bans, user_id), requestOptions); 15 | -------------------------------------------------------------------------------- /src/actions/voice.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as types from '../types'; 4 | 5 | export const ListRegions = (requestOptions?: RequestOptions) => 6 | Request(METHODS.GET, Path(PATHS.voice, PATHS.regions), requestOptions); 7 | 8 | export const UpdateCurrentState = (guild_id: string, params: { 9 | channel_id: string; 10 | suppress?: boolean; 11 | request_to_speak_timestamp?: string | null; 12 | }, requestOptions?: RequestOptions) => 13 | Request(METHODS.PATCH, Path(PATHS.guilds, guild_id, PATHS.voice_states, PATHS.me), requestOptions, params); 14 | 15 | export const UpdateUserState = (guild_id: string, user_id: string, params: { 16 | channel_id: string; 17 | suppress?: boolean; 18 | }, requestOptions?: RequestOptions) => 19 | Request(METHODS.PATCH, Path(PATHS.guilds, guild_id, PATHS.voice_states, user_id), requestOptions, params); 20 | -------------------------------------------------------------------------------- /src/authorization.ts: -------------------------------------------------------------------------------- 1 | import { TokenTypes } from './helpers'; 2 | 3 | export class Authorization { 4 | private _type: TokenTypes; 5 | private _token: string; 6 | private _cache = ''; 7 | 8 | constructor( 9 | token: string, 10 | type: TokenTypes = TokenTypes.BOT 11 | ) { 12 | this._token = token; 13 | this._type = type; 14 | this._update(); 15 | } 16 | 17 | private _update = () => 18 | this._cache = this._type ? 19 | `${this._type} ${this._token}` : 20 | this._token; 21 | 22 | get type() { return this._type; }; 23 | 24 | set type(value: TokenTypes) { 25 | this._type = value; 26 | this._update(); 27 | }; 28 | 29 | get token() { return this._token; }; 30 | 31 | set token(value: string) { 32 | this._token = value; 33 | this._update(); 34 | }; 35 | 36 | get value() { return this._cache; }; 37 | 38 | toString = () => this._cache; 39 | } 40 | -------------------------------------------------------------------------------- /src/actions/reaction.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | 4 | export const Add = (channel_id: string, message_id: string, emoji: string, requestOptions?: RequestOptions) => 5 | Request(METHODS.PUT, Path(PATHS.channels, channel_id, PATHS.messages, message_id, PATHS.reactions, encodeURIComponent(emoji), PATHS.me), requestOptions); 6 | 7 | export const DeleteOwn = (channel_id: string, message_id: string, emoji: string, requestOptions?: RequestOptions) => 8 | Request(METHODS.DELETE, Path(PATHS.channels, channel_id, PATHS.messages, message_id, PATHS.reactions, encodeURIComponent(emoji), PATHS.me), requestOptions); 9 | 10 | export const Delete = (channel_id: string, message_id: string, user_id: string, emoji: string, requestOptions?: RequestOptions) => 11 | Request(METHODS.DELETE, Path(PATHS.channels, channel_id, PATHS.messages, message_id, PATHS.reactions, encodeURIComponent(emoji), user_id), requestOptions); 12 | -------------------------------------------------------------------------------- /src/actions/widget.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path, Query } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as helpers from '../helpers'; 4 | import type * as types from '../types'; 5 | 6 | export const GetSettings = (guild_id: string, requestOptions?: RequestOptions) => 7 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.widget), requestOptions); 8 | 9 | export const Modify = (guild_id: string, params: types.GuildWidgetSettings, requestOptions?: RequestOptions) => 10 | Request(METHODS.PATCH, Path(PATHS.guilds, guild_id, PATHS.widget), requestOptions, params); 11 | 12 | export const Get = (guild_id: string, requestOptions?: RequestOptions) => 13 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.widget_json), requestOptions); 14 | 15 | export const GetImage = (guild_id: string, params?: { 16 | style?: helpers.WidgetStyleOptions; 17 | }, requestOptions?: RequestOptions) => 18 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.widget_png) + Query(params), requestOptions); 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Hanabishi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Hanabishi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/actions/sticker.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as types from '../types'; 4 | 5 | export const Get = (sticker_id: string, requestOptions?: RequestOptions) => 6 | Request(METHODS.GET, Path(PATHS.stickers, sticker_id), requestOptions); 7 | 8 | export const GetFromGuild = (guild_id: string, sticker_id: string, requestOptions?: RequestOptions) => 9 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.stickers, sticker_id), requestOptions); 10 | 11 | // Create: TODO 12 | 13 | export const Modify = (guild_id: string, sticker_id: string, params: { 14 | name?: string; 15 | description?: string | null; 16 | tags?: string; 17 | }, requestOptions?: RequestOptions) => 18 | Request(METHODS.PATCH, Path(PATHS.guilds, guild_id, PATHS.stickers, sticker_id), requestOptions, params); 19 | 20 | export const Delete = (guild_id: string, sticker_id: string, requestOptions?: RequestOptions) => 21 | Request(METHODS.DELETE, Path(PATHS.guilds, guild_id, PATHS.stickers, sticker_id), requestOptions); 22 | -------------------------------------------------------------------------------- /src/actions/emoji.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as types from '../types'; 4 | 5 | export const Get = (guild_id: string, emoji_id: string, requestOptions?: RequestOptions) => 6 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.emojis, emoji_id), requestOptions); 7 | 8 | export const Add = (guild_id: string, params: { 9 | name: string; 10 | image: string; 11 | roles?: string[]; 12 | }, requestOptions?: RequestOptions) => 13 | Request(METHODS.POST, Path(PATHS.guilds, guild_id, PATHS.emojis), requestOptions, params); 14 | 15 | export const Modify = (guild_id: string, emoji_id: string, params: { 16 | name?: string; 17 | roles?: string[] | null; 18 | }, requestOptions?: RequestOptions) => 19 | Request(METHODS.PATCH, Path(PATHS.guilds, guild_id, PATHS.emojis, emoji_id), requestOptions, params); 20 | 21 | export const Delete = (guild_id: string, emoji_id: string, requestOptions?: RequestOptions) => 22 | Request(METHODS.DELETE, Path(PATHS.guilds, guild_id, PATHS.emojis, emoji_id), requestOptions); 23 | -------------------------------------------------------------------------------- /src/actions/invite.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path, Query } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as helpers from '../helpers'; 4 | import type * as types from '../types'; 5 | 6 | export const Create = (channel_id: string, params: { 7 | max_age?: number; 8 | max_uses?: number; 9 | temporary?: boolean; 10 | unique?: boolean; 11 | target_type?: helpers.InviteTargetTypes; 12 | target_user_id?: string; 13 | target_application_id?: string; 14 | }, requestOptions?: RequestOptions) => 15 | Request(METHODS.POST, Path(PATHS.channels, channel_id, PATHS.invites), requestOptions, params); 16 | 17 | export const Get = (invite_code: string, params?: { 18 | with_counts?: boolean; 19 | with_expiration?: boolean; 20 | guild_scheduled_event_id?: string; 21 | }, requestOptions?: RequestOptions) => 22 | Request(METHODS.GET, Path(PATHS.invites, invite_code) + Query(params), requestOptions); 23 | 24 | export const Delete = (invite_code: string, requestOptions?: RequestOptions) => 25 | Request(METHODS.DELETE, Path(PATHS.invites, invite_code), requestOptions); 26 | -------------------------------------------------------------------------------- /src/actions/stageinstance.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as helpers from '../helpers'; 4 | import type * as types from '../types'; 5 | 6 | export const Create = (params: { 7 | channel_id: string; 8 | topic: string; 9 | privacy_level?: helpers.PrivacyLevels; 10 | send_start_notification?: boolean; 11 | }, requestOptions?: RequestOptions) => 12 | Request(METHODS.POST, PATHS.stage_instances, requestOptions, params); 13 | 14 | export const Get = (channel_id: string, requestOptions?: RequestOptions) => 15 | Request(METHODS.GET, Path(PATHS.stage_instances, channel_id), requestOptions); 16 | 17 | export const Modify = (channel_id: string, params: { 18 | topic?: string; 19 | privacy_level?: helpers.PrivacyLevels; 20 | }, requestOptions?: RequestOptions) => 21 | Request(METHODS.PATCH, Path(PATHS.stage_instances, channel_id), requestOptions, params); 22 | 23 | export const Delete = (channel_id: string, requestOptions?: RequestOptions) => 24 | Request(METHODS.DELETE, Path(PATHS.stage_instances, channel_id), requestOptions); 25 | -------------------------------------------------------------------------------- /src/actions/role.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as types from '../types'; 4 | 5 | export const Create = (guild_id: string, params?: { 6 | name?: string; 7 | permissions?: string; 8 | color?: number; 9 | hoist?: boolean; 10 | icon?: string; 11 | unicode_emoji?: string; 12 | mentionable?: boolean; 13 | }, requestOptions?: RequestOptions) => 14 | Request(METHODS.POST, Path(PATHS.guilds, guild_id, PATHS.roles), requestOptions, params); 15 | 16 | export const Modify = (guild_id: string, role_id: string, params?: { 17 | name?: string | null; 18 | permissions?: string | null; 19 | color?: number | null; 20 | hoist?: boolean | null; 21 | icon?: string | null; 22 | unicode_emoji?: string | null; 23 | mentionable?: boolean | null; 24 | }, requestOptions?: RequestOptions) => 25 | Request(METHODS.PATCH, Path(PATHS.guilds, guild_id, PATHS.roles, role_id), requestOptions, params); 26 | 27 | export const Delete = (guild_id: string, role_id: string, requestOptions?: RequestOptions) => 28 | Request(METHODS.DELETE, Path(PATHS.guilds, guild_id, PATHS.roles, role_id), requestOptions); 29 | -------------------------------------------------------------------------------- /src/actions.ts: -------------------------------------------------------------------------------- 1 | import { SetDefOptions } from './request'; 2 | 3 | export const setDefaultRequestOptions = SetDefOptions; 4 | 5 | export * as Application from './actions/application'; 6 | export * as Ban from './actions/ban'; 7 | export * as Channel from './actions/channel'; 8 | export * as DM from './actions/dm'; 9 | export * as Emoji from './actions/emoji'; 10 | export * as Gateway from './actions/gateway'; 11 | export * as GroupDM from './actions/groupdm'; 12 | export * as Guild from './actions/guild'; 13 | export * as Invite from './actions/invite'; 14 | export * as Member from './actions/member'; 15 | export * as Message from './actions/message'; 16 | export * as OAuth2 from './actions/oauth2'; 17 | export * as Reaction from './actions/reaction'; 18 | export * as Role from './actions/role'; 19 | export * as ScheduledEvent from './actions/scheduledevent'; 20 | export * as StageInstance from './actions/stageinstance'; 21 | export * as Sticker from './actions/sticker'; 22 | export * as StickerPacks from './actions/stickerpacks'; 23 | export * as Template from './actions/template'; 24 | export * as Thread from './actions/thread'; 25 | export * as User from './actions/user'; 26 | export * as Voice from './actions/voice'; 27 | export * as Webhook from './actions/webhook'; 28 | export * as WelcomeScreen from './actions/welcomescreen'; 29 | export * as Widget from './actions/widget'; 30 | -------------------------------------------------------------------------------- /src/actions/template.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as types from '../types'; 4 | 5 | export const Get = (template_code: string, requestOptions?: RequestOptions) => 6 | Request(METHODS.GET, Path(PATHS.guilds, PATHS.templates, template_code), requestOptions); 7 | 8 | export const Create = (guild_id: string, params: { 9 | name: string; 10 | description?: string; 11 | }, requestOptions?: RequestOptions) => 12 | Request(METHODS.POST, Path(PATHS.guilds, guild_id, PATHS.templates), requestOptions, params); 13 | 14 | export const Sync = (guild_id: string, template_code: string, requestOptions?: RequestOptions) => 15 | Request(METHODS.PUT, Path(PATHS.guilds, guild_id, PATHS.templates, template_code), requestOptions); 16 | 17 | export const Modify = (guild_id: string, template_code: string, params: { 18 | name?: string; 19 | description?: string; 20 | }, requestOptions?: RequestOptions) => 21 | Request(METHODS.PATCH, Path(PATHS.guilds, guild_id, PATHS.templates, template_code), requestOptions, params); 22 | 23 | export const Delete = (guild_id: string, template_code: string, requestOptions?: RequestOptions) => 24 | Request(METHODS.DELETE, Path(PATHS.guilds, guild_id, PATHS.templates, template_code), requestOptions); 25 | -------------------------------------------------------------------------------- /src/actions/groupdm.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as types from '../types'; 4 | 5 | export const AddRecipient = (channel_id: string, user_id: string, params: { 6 | access_token: string; 7 | nick: string; 8 | }, requestOptions?: RequestOptions) => 9 | Request(METHODS.PUT, Path(PATHS.channels, channel_id, PATHS.recipients, user_id), requestOptions, params); 10 | 11 | export const RemoveRecipient = (channel_id: string, user_id: string, requestOptions?: RequestOptions) => 12 | Request(METHODS.DELETE, Path(PATHS.channels, channel_id, PATHS.recipients, user_id), requestOptions); 13 | 14 | export const Modify = (id: string, params: { 15 | name?: string; 16 | icon?: string; 17 | }, requestOptions?: RequestOptions) => 18 | Request(METHODS.PATCH, Path(PATHS.channels, id), requestOptions, params); 19 | 20 | export const Create = (params: { 21 | access_tokens: string[]; 22 | nicks: { 23 | [id: string]: string; 24 | }; 25 | }, requestOptions?: RequestOptions) => 26 | Request(METHODS.POST, Path(PATHS.users, PATHS.me, PATHS.channels), requestOptions, params); 27 | 28 | export const Close = (channel_id: string, requestOptions?: RequestOptions) => 29 | Request(METHODS.DELETE, Path(PATHS.channels, channel_id), requestOptions); 30 | -------------------------------------------------------------------------------- /src/actions/oauth2.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path, Param } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as helpers from '../helpers'; 4 | import type * as types from '../types'; 5 | 6 | export const TokenExchange = (params: ({ 7 | client_id: string; 8 | client_secret: string; 9 | redirect_uri: string; 10 | scope: helpers.OAuth2Scopes | string; 11 | } & ({ 12 | grant_type: helpers.OAuth2GrantTypes.AUTHORIZATION_CODE; 13 | code: string; 14 | } | { 15 | grant_type: helpers.OAuth2GrantTypes.REFRESH_TOKEN; 16 | refresh_token: string; 17 | })), requestOptions?: RequestOptions) => 18 | Request<{ 19 | access_token: string; 20 | token_type: helpers.TokenTypes.BEARER; 21 | expires_in: number; 22 | refresh_token: string; 23 | scope: helpers.OAuth2Scopes | string; 24 | }>(METHODS.POST, Path(PATHS.oauth2, PATHS.token), requestOptions, Param(params)); 25 | 26 | export const GetCurrentApplicationInformation = (requestOptions?: RequestOptions) => 27 | Request(METHODS.GET, Path(PATHS.oauth2, PATHS.applications, PATHS.me), requestOptions); 28 | 29 | export const GetCurrentAuthorizationInformation = (requestOptions?: RequestOptions) => 30 | Request<{ 31 | application: types.Application, 32 | scopes: string[]; 33 | expires: string; 34 | user?: types.User; 35 | }>(METHODS.GET, Path(PATHS.oauth2, PATHS.me), requestOptions); 36 | -------------------------------------------------------------------------------- /src/actions/user.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path, Query } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as types from '../types'; 4 | 5 | export const GetCurrent = (requestOptions?: RequestOptions) => 6 | Request(METHODS.GET, Path(PATHS.users, PATHS.me), requestOptions); 7 | 8 | export const Get = (user_id: string, requestOptions?: RequestOptions) => 9 | Request(METHODS.GET, Path(PATHS.users, user_id), requestOptions); 10 | 11 | export const ModifyCurrent = (params: { 12 | username?: string; 13 | avatar?: string | null; 14 | }, requestOptions?: RequestOptions) => 15 | Request(METHODS.PATCH, Path(PATHS.users, PATHS.me), requestOptions, params); 16 | 17 | export const GetCurrentGuilds = (params?: { 18 | limit?: number; 19 | } & ({ 20 | before?: string; 21 | after?: undefined; 22 | } | { 23 | before?: undefined; 24 | after?: string; 25 | }), requestOptions?: RequestOptions) => 26 | Request<(types.Guild & { 27 | owner: boolean; 28 | permissions: string; 29 | })[]>(METHODS.GET, Path(PATHS.users, PATHS.me, PATHS.guilds) + Query(params), requestOptions); 30 | 31 | export const GetCurrentMember = (guild_id: string, requestOptions?: RequestOptions) => 32 | Request(METHODS.GET, Path(PATHS.users, PATHS.me, PATHS.guilds, guild_id, PATHS.member), requestOptions); 33 | 34 | export const LeaveGuild = (guild_id: string, requestOptions?: RequestOptions) => 35 | Request(METHODS.DELETE, Path(PATHS.users, PATHS.me, PATHS.guilds, guild_id), requestOptions); 36 | 37 | export const GetConnections = (requestOptions?: RequestOptions) => 38 | Request(METHODS.GET, Path(PATHS.users, PATHS.me, PATHS.connections), requestOptions); 39 | -------------------------------------------------------------------------------- /src/_common.ts: -------------------------------------------------------------------------------- 1 | import { RequestOptions, request } from 'https'; 2 | 3 | // @internal 4 | export const SafeJsonParse = (data?: string) => 5 | data ? JSON.parse(data) as T : null; 6 | 7 | // @internal 8 | export const Sleep = (time: number) => 9 | new Promise((resolve) => setTimeout(resolve, time)); 10 | 11 | // @internal 12 | export const TimestampString = (timestamp: number) => { 13 | const str = new Date(timestamp).toISOString(); 14 | return `${str.slice(0, 10)} ${str.slice(11, -5)} UTC`; 15 | }; 16 | 17 | // @internal 18 | export const HttpsRequest = ( 19 | url: string, 20 | options: RequestOptions, 21 | content?: string | Buffer, 22 | ) => new Promise<{ 23 | code: number; 24 | data?: string; 25 | }>((resolve, reject) => { 26 | const req = request(url, options, (response) => { 27 | const code = response.statusCode; 28 | if(!code) return reject('Unknown response.'); 29 | 30 | const ReturnResult = (data?: string) => resolve({ code, data }); 31 | 32 | const chunks: Buffer[] = []; 33 | let totalLength = 0; 34 | 35 | response.on('data', (chunk: Buffer) => { 36 | chunks.push(chunk); 37 | totalLength += chunk.length; 38 | }); 39 | 40 | response.on('end', () => { 41 | if(!response.complete) 42 | return reject('Response error.'); 43 | 44 | if(totalLength == 0) 45 | return ReturnResult(); 46 | 47 | if(chunks.length == 1) 48 | return ReturnResult(String(chunks[0])); 49 | 50 | return ReturnResult(String(Buffer.concat(chunks, totalLength))); 51 | }); 52 | }); 53 | 54 | req.on('error', reject); 55 | req.on('timeout', () => reject('Request timeout.')); 56 | 57 | req.end(content); 58 | }); 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 output 82 | .nuxt 83 | 84 | # gatsby files 85 | .cache/ 86 | public 87 | 88 | # vuepress build output 89 | .vuepress/dist 90 | 91 | # Serverless directories 92 | .serverless/ 93 | 94 | # FuseBox cache 95 | .fusebox/ 96 | 97 | # DynamoDB Local files 98 | .dynamodb/ 99 | 100 | # TernJS port file 101 | .tern-port 102 | 103 | # Build 104 | dist/ 105 | 106 | # Ignore lockfile for library 107 | package-lock.json 108 | -------------------------------------------------------------------------------- /src/actions/member.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as types from '../types'; 4 | 5 | export const Get = (guild_id: string, user_id: string, requestOptions?: RequestOptions) => 6 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.members, user_id), requestOptions); 7 | 8 | export const Add = (guild_id: string, user_id: string, params: { 9 | access_token: string; 10 | nick?: string; 11 | roles?: string[]; 12 | mute?: boolean; 13 | deaf?: boolean; 14 | }, requestOptions?: RequestOptions) => 15 | Request(METHODS.PUT, Path(PATHS.guilds, guild_id, PATHS.members, user_id), requestOptions, params); 16 | 17 | export const Modify = (guild_id: string, user_id: string, params: { 18 | nick?: string | null; 19 | roles?: string[] | null; 20 | mute?: boolean | null; 21 | deaf?: boolean | null; 22 | channel_id?: string | null; 23 | communication_disabled_until?: string | null; 24 | }, requestOptions?: RequestOptions) => 25 | Request(METHODS.PATCH, Path(PATHS.guilds, guild_id, PATHS.members, user_id), requestOptions, params); 26 | 27 | export const ModifyCurrent = (guild_id: string, params: { 28 | nick?: string | null; 29 | }, requestOptions?: RequestOptions) => 30 | Request(METHODS.PATCH, Path(PATHS.guilds, guild_id, PATHS.members, PATHS.me), requestOptions, params); 31 | 32 | export const AddRole = (guild_id: string, user_id: string, role_id: string, requestOptions?: RequestOptions) => 33 | Request(METHODS.PUT, Path(PATHS.guilds, guild_id, PATHS.members, user_id, PATHS.roles, role_id), requestOptions); 34 | 35 | export const RemoveRole = (guild_id: string, user_id: string, role_id: string, requestOptions?: RequestOptions) => 36 | Request(METHODS.DELETE, Path(PATHS.guilds, guild_id, PATHS.members, user_id, PATHS.roles, role_id), requestOptions); 37 | 38 | export const Remove = (guild_id: string, user_id: string, requestOptions?: RequestOptions) => 39 | Request(METHODS.DELETE, Path(PATHS.guilds, guild_id, PATHS.members, user_id), requestOptions); 40 | -------------------------------------------------------------------------------- /src/actions/_common.ts: -------------------------------------------------------------------------------- 1 | import { URLSearchParams } from 'url'; 2 | 3 | // @internal 4 | export const 5 | Path = (...paths: string[]) => paths.join('/'), 6 | Param = (params: any) => String(new URLSearchParams(params)), 7 | Query = (params: any) => params ? '?' + Param(params) : ''; 8 | 9 | // @internal 10 | export const enum METHODS { 11 | GET = 'GET', 12 | POST = 'POST', 13 | PUT = 'PUT', 14 | DELETE = 'DELETE', 15 | PATCH = 'PATCH', 16 | } 17 | 18 | // @internal 19 | export const enum PATHS { 20 | active = 'active', 21 | applications = 'applications', 22 | archived = 'archived', 23 | auditLogs = 'audit-logs', 24 | bans = 'bans', 25 | bot = 'bot', 26 | bulk_delete = 'bulk-delete', 27 | callback = 'callback', 28 | channels = 'channels', 29 | commands = 'commands', 30 | connections = 'connections', 31 | crosspost = 'crosspost', 32 | emojis = 'emojis', 33 | followers = 'followers', 34 | gateway = 'gateway', 35 | github = 'github', 36 | guilds = 'guilds', 37 | integrations = 'integrations', 38 | interactions = 'interactions', 39 | invites = 'invites', 40 | me = '@me', 41 | member = 'member', 42 | members = 'members', 43 | messages = 'messages', 44 | nick = 'nick', 45 | oauth2 = 'oauth2', 46 | original = '@original', 47 | permissions = 'permissions', 48 | pins = 'pins', 49 | preview = 'preview', 50 | private = 'private', 51 | prune = 'prune', 52 | public = 'public', 53 | reactions = 'reactions', 54 | recipients = 'recipients', 55 | regions = 'regions', 56 | roles = 'roles', 57 | scheduled_events = 'scheduled-events', 58 | search = 'search', 59 | slack = 'slack', 60 | stage_instances = 'stage-instances', 61 | sticker_packs = 'sticker-packs', 62 | stickers = 'stickers', 63 | templates = 'templates', 64 | thread_members = 'thread-members', 65 | threads = 'threads', 66 | token = 'token', 67 | typing = 'typing', 68 | users = 'users', 69 | vanity_url = 'vanity-url', 70 | voice = 'voice', 71 | voice_states = 'voice-states', 72 | webhooks = 'webhooks', 73 | welcome_screen = 'welcome-screen', 74 | widget = 'widget', 75 | widget_json = 'widget.json', 76 | widget_png = 'widget.png', 77 | } 78 | -------------------------------------------------------------------------------- /src/actions/scheduledevent.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path, Query } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as helpers from '../helpers'; 4 | import type * as types from '../types'; 5 | 6 | export const Create = (guild_id: string, params: { 7 | channel_id?: string; 8 | entity_metadata?: types.ScheduledEventEntityMetadata; 9 | name: string; 10 | privacy_level: helpers.PrivacyLevels; 11 | scheduled_start_time: string; 12 | scheduled_end_time?: string; 13 | description?: string; 14 | entity_type: helpers.ScheduledEventEntityTypes; 15 | image?: string; 16 | }, requestOptions?: RequestOptions) => 17 | Request(METHODS.POST, Path(PATHS.guilds, guild_id, PATHS.scheduled_events), requestOptions, params); 18 | 19 | export const Get = (guild_id: string, event_id: string, params?: { 20 | with_user_count?: boolean; 21 | }, requestOptions?: RequestOptions) => 22 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.scheduled_events, event_id) + Query(params), requestOptions); 23 | 24 | export const Modify = (guild_id: string, event_id: string, params: { 25 | channel_id?: string | null; 26 | entity_metadata?: types.ScheduledEventEntityMetadata | null; 27 | name?: string; 28 | privacy_level?: helpers.PrivacyLevels; 29 | scheduled_start_time?: string; 30 | scheduled_end_time?: string; 31 | description?: string | null; 32 | entity_type?: helpers.ScheduledEventEntityTypes; 33 | status?: helpers.ScheduledEventStatuses; 34 | image?: string | null; 35 | }, requestOptions?: RequestOptions) => 36 | Request(METHODS.PATCH, Path(PATHS.guilds, guild_id, PATHS.scheduled_events, event_id), requestOptions, params); 37 | 38 | export const Delete = (guild_id: string, event_id: string, requestOptions?: RequestOptions) => 39 | Request(METHODS.DELETE, Path(PATHS.guilds, guild_id, PATHS.scheduled_events, event_id), requestOptions); 40 | 41 | export const GetUsers = (guild_id: string, event_id: string, params?: { 42 | limit?: number; 43 | with_member?: boolean; 44 | } & ({ 45 | before?: string; 46 | after?: undefined; 47 | } | { 48 | before?: undefined; 49 | after?: string; 50 | }), requestOptions?: RequestOptions) => 51 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.scheduled_events, event_id, PATHS.users) + Query(params), requestOptions); 52 | -------------------------------------------------------------------------------- /src/request.ts: -------------------------------------------------------------------------------- 1 | import { HttpsRequest, SafeJsonParse, Sleep } from './_common'; 2 | import { API_PATH } from './helpers'; 3 | import { Authorization } from './authorization'; 4 | 5 | const 6 | DEFAULT_CONNECTION_TIMEOUT = 5000, 7 | DEFAULT_RETRY_COUNT = 5; 8 | 9 | const enum Headers { 10 | ContentType = 'Content-Type', 11 | ContentLength = 'Content-Length', 12 | Authorization = 'Authorization', 13 | } 14 | 15 | const enum ContentTypes { 16 | Form = 'application/x-www-form-urlencoded', 17 | Json = 'application/json', 18 | } 19 | 20 | export type RateLimitResponse = { 21 | message: string; 22 | retry_after: number; 23 | global: boolean; 24 | }; 25 | 26 | export type RequestOptions = { 27 | authorization?: Authorization; 28 | connectionTimeout?: number; 29 | rateLimit?: { 30 | retryCount?: number; 31 | callback?: (response: RateLimitResponse, attempts: number) => void; 32 | }; 33 | }; 34 | 35 | let defOptions: RequestOptions = {}; 36 | 37 | // @internal 38 | export const SetDefOptions = (options?: RequestOptions) => 39 | defOptions = options ?? {}; 40 | 41 | // @internal 42 | export const Request = async ( 43 | method: string, 44 | endpoint: string, 45 | { 46 | authorization, 47 | connectionTimeout: timeout = DEFAULT_CONNECTION_TIMEOUT, 48 | rateLimit: { 49 | retryCount = DEFAULT_RETRY_COUNT, 50 | callback: rateLimitCallback, 51 | } = {}, 52 | } = defOptions, 53 | data?: object | string | null, 54 | ) => { 55 | const 56 | url = `${API_PATH}/${endpoint}`, 57 | headers: Record = {}, 58 | requestOptions = { method, headers, timeout }; 59 | 60 | let content: string | undefined; 61 | 62 | if(typeof data == 'object') { 63 | content = JSON.stringify(data); 64 | headers[Headers.ContentType] = ContentTypes.Json; 65 | } else if(typeof data == 'string') { 66 | content = data; 67 | headers[Headers.ContentType] = ContentTypes.Form; 68 | } 69 | 70 | if(content) 71 | headers[Headers.ContentLength] = String(Buffer.byteLength(content)); 72 | 73 | if(authorization instanceof Authorization) 74 | headers[Headers.Authorization] = String(authorization); 75 | 76 | let attempts = 0; 77 | 78 | while(true) { 79 | const { code, data } = await HttpsRequest(url, requestOptions, content); 80 | 81 | if((code >= 200) && (code < 300)) 82 | return SafeJsonParse(data) as T; 83 | 84 | if((code >= 400) && (code < 500)) { 85 | if(code != 429) throw { 86 | code, 87 | response: SafeJsonParse(data), 88 | }; 89 | 90 | const response = SafeJsonParse(data); 91 | if(!response) throw { code }; 92 | 93 | attempts++; 94 | rateLimitCallback?.(response, attempts); 95 | 96 | const { retry_after } = response; 97 | if(!(retry_after && (attempts < retryCount))) 98 | throw { code, response }; 99 | 100 | await Sleep(Math.ceil(Number(retry_after) * 1000)); 101 | continue; 102 | } 103 | 104 | throw { code }; 105 | } 106 | }; 107 | -------------------------------------------------------------------------------- /src/actions/message.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path, Query } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as helpers from '../helpers'; 4 | import type * as types from '../types'; 5 | 6 | export const Get = (channel_id: string, message_id: string, requestOptions?: RequestOptions) => 7 | Request(METHODS.GET, Path(PATHS.channels, channel_id, PATHS.messages, message_id), requestOptions); 8 | 9 | export const Create = (channel_id: string, params: { 10 | content?: string; 11 | nonce?: number | string; 12 | tts?: string; 13 | embeds?: types.Embed[]; 14 | allowed_mentions?: types.AllowedMentions; 15 | message_reference?: { 16 | message_id: string; 17 | channel_id?: string; 18 | guild_id?: string; 19 | fail_if_not_exists?: boolean; 20 | }; 21 | components?: types.ActionRow[]; 22 | sticker_ids?: string[]; 23 | flags?: helpers.MessageFlags; 24 | }, requestOptions?: RequestOptions) => 25 | Request(METHODS.POST, Path(PATHS.channels, channel_id, PATHS.messages), requestOptions, params); 26 | 27 | export const Crosspost = (channel_id: string, message_id: string, requestOptions?: RequestOptions) => 28 | Request(METHODS.POST, Path(PATHS.channels, channel_id, PATHS.messages, message_id, PATHS.crosspost), requestOptions); 29 | 30 | export const Delete = (channel_id: string, message_id: string, requestOptions?: RequestOptions) => 31 | Request(METHODS.DELETE, Path(PATHS.channels, channel_id, PATHS.messages, message_id), requestOptions); 32 | 33 | export const Edit = (channel_id: string, message_id: string, params: { 34 | content?: string; 35 | embeds?: types.Embed[]; 36 | flags?: helpers.MessageFlags; 37 | allowed_mentions?: types.AllowedMentions; 38 | components?: types.ActionRow[]; 39 | attachments?: types.Attachment[]; 40 | }, requestOptions?: RequestOptions) => 41 | Request(METHODS.PATCH, Path(PATHS.channels, channel_id, PATHS.messages, message_id), requestOptions, params); 42 | 43 | export const Pin = (channel_id: string, message_id: string, requestOptions?: RequestOptions) => 44 | Request(METHODS.PUT, Path(PATHS.channels, channel_id, PATHS.pins, message_id), requestOptions); 45 | 46 | export const Unpin = (channel_id: string, message_id: string, requestOptions?: RequestOptions) => 47 | Request(METHODS.DELETE, Path(PATHS.channels, channel_id, PATHS.pins, message_id), requestOptions); 48 | 49 | export const GetReactions = (channel_id: string, message_id: string, emoji: string, params?: { 50 | after?: string; 51 | limit?: number; 52 | }, requestOptions?: RequestOptions) => 53 | Request(METHODS.GET, Path(PATHS.channels, channel_id, PATHS.messages, message_id, PATHS.reactions, encodeURIComponent(emoji)) + Query(params), requestOptions); 54 | 55 | export const DeleteAllReactions = (channel_id: string, message_id: string, requestOptions?: RequestOptions) => 56 | Request(METHODS.DELETE, Path(PATHS.channels, channel_id, PATHS.messages, message_id, PATHS.reactions), requestOptions); 57 | 58 | export const DeleteAllReactionsForEmoji = (channel_id: string, message_id: string, emoji: string, requestOptions?: RequestOptions) => 59 | Request(METHODS.DELETE, Path(PATHS.channels, channel_id, PATHS.messages, message_id, PATHS.reactions, encodeURIComponent(emoji)), requestOptions); 60 | -------------------------------------------------------------------------------- /src/actions/thread.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as helpers from '../helpers'; 4 | import type * as types from '../types'; 5 | 6 | export const Modify = (thread_id: string, params: { 7 | name?: string; 8 | archived?: boolean; 9 | auto_archive_duration?: helpers.ThreadArchiveDurations; 10 | locked?: boolean; 11 | invitable?: boolean; 12 | rate_limit_per_user?: number | null; 13 | flags?: helpers.MessageFlags; 14 | }, requestOptions?: RequestOptions) => 15 | Request(METHODS.PATCH, Path(PATHS.channels, thread_id), requestOptions, params); 16 | 17 | export const Delete = (thread_id: string, requestOptions?: RequestOptions) => 18 | Request(METHODS.DELETE, Path(PATHS.channels, thread_id), requestOptions); 19 | 20 | export const StartWithMessage = (channel_id: string, message_id: string, params: { 21 | name: string; 22 | auto_archive_duration?: helpers.ThreadArchiveDurations; 23 | rate_limit_per_user?: number | null; 24 | }, requestOptions?: RequestOptions) => 25 | Request; 27 | }>(METHODS.POST, Path(PATHS.channels, channel_id, PATHS.messages, message_id, PATHS.threads), requestOptions, params); 28 | 29 | export const Start = (channel_id: string, params: { 30 | name: string; 31 | type: T; 32 | auto_archive_duration?: helpers.ThreadArchiveDurations; 33 | rate_limit_per_user?: number | null; 34 | } & ({ 35 | type: helpers.ChannelTypes.GUILD_PRIVATE_THREAD; 36 | invitable?: boolean; 37 | } | {}), requestOptions?: RequestOptions) => 38 | Request(METHODS.POST, Path(PATHS.channels, channel_id, PATHS.threads), requestOptions, params); 41 | 42 | export const StartInForum = (channel_id: string, params: { 43 | name: string; 44 | auto_archive_duration?: helpers.ThreadArchiveDurations; 45 | rate_limit_per_user?: number | null; 46 | message: { 47 | content?: string; 48 | embeds?: types.Embed[]; 49 | allowed_mentions?: types.AllowedMentions; 50 | components?: types.ActionRow[]; 51 | sticker_ids?: string[]; 52 | flags?: helpers.MessageFlags; 53 | }; 54 | }, requestOptions?: RequestOptions) => 55 | Request(METHODS.POST, Path(PATHS.channels, channel_id, PATHS.threads), requestOptions, params); 59 | 60 | export const Join = (thread_id: string, requestOptions?: RequestOptions) => 61 | Request(METHODS.PUT, Path(PATHS.channels, thread_id, PATHS.thread_members, PATHS.me), requestOptions); 62 | 63 | export const AddMember = (thread_id: string, user_id: string, requestOptions?: RequestOptions) => 64 | Request(METHODS.PUT, Path(PATHS.channels, thread_id, PATHS.thread_members, user_id), requestOptions); 65 | 66 | export const Leave = (thread_id: string, requestOptions?: RequestOptions) => 67 | Request(METHODS.DELETE, Path(PATHS.channels, thread_id, PATHS.thread_members, PATHS.me), requestOptions); 68 | 69 | export const RemoveMember = (thread_id: string, user_id: string, requestOptions?: RequestOptions) => 70 | Request(METHODS.DELETE, Path(PATHS.channels, thread_id, PATHS.thread_members, user_id), requestOptions); 71 | 72 | export const GetMember = (thread_id: string, user_id: string, requestOptions?: RequestOptions) => 73 | Request(METHODS.GET, Path(PATHS.channels, thread_id, PATHS.thread_members, user_id), requestOptions); 74 | 75 | export const ListMembers = (thread_id: string, requestOptions?: RequestOptions) => 76 | Request(METHODS.GET, Path(PATHS.channels, thread_id, PATHS.thread_members), requestOptions); 77 | -------------------------------------------------------------------------------- /src/actions/webhook.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path, Query } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as helpers from '../helpers'; 4 | import type * as types from '../types'; 5 | 6 | export const Create = (channel_id: string, params: { 7 | name: string; 8 | avatar?: string | null; 9 | }, requestOptions?: RequestOptions) => 10 | Request(METHODS.POST, Path(PATHS.channels, channel_id, PATHS.webhooks), requestOptions, params); 11 | 12 | export const Get = (webhook_id: string, requestOptions?: RequestOptions) => 13 | Request(METHODS.GET, Path(PATHS.webhooks, webhook_id), requestOptions); 14 | 15 | export const GetWithToken = (webhook_id: string, webhook_token: string, requestOptions?: RequestOptions) => 16 | Request(METHODS.GET, Path(PATHS.webhooks, webhook_id, webhook_token), requestOptions); 17 | 18 | export const Modify = (webhook_id: string, params: { 19 | name?: string; 20 | avatar?: string | null; 21 | channel_id?: string; 22 | }, requestOptions?: RequestOptions) => 23 | Request(METHODS.PATCH, Path(PATHS.webhooks, webhook_id), requestOptions, params); 24 | 25 | export const ModifyWithToken = (webhook_id: string, webhook_token: string, params: { 26 | name?: string; 27 | avatar?: string | null; 28 | }, requestOptions?: RequestOptions) => 29 | Request(METHODS.PATCH, Path(PATHS.webhooks, webhook_id, webhook_token), requestOptions, params); 30 | 31 | export const Delete = (webhook_id: string, requestOptions?: RequestOptions) => 32 | Request(METHODS.DELETE, Path(PATHS.webhooks, webhook_id), requestOptions); 33 | 34 | export const DeleteWithToken = (webhook_id: string, webhook_token: string, requestOptions?: RequestOptions) => 35 | Request(METHODS.DELETE, Path(PATHS.webhooks, webhook_id, webhook_token), requestOptions); 36 | 37 | export const Execute = (webhook_id: string, webhook_token: string, params1: { 38 | content?: string; 39 | username?: string; 40 | avatar_url?: string; 41 | tts?: string; 42 | embeds?: types.Embed[]; 43 | allowed_mentions?: types.AllowedMentions; 44 | components?: types.ActionRow[]; 45 | flags?: helpers.MessageFlags; 46 | thread_name?: string; 47 | }, params2?: { 48 | wait?: T; 49 | thread_id?: string; 50 | }, requestOptions?: RequestOptions) => 51 | Request(METHODS.POST, Path(PATHS.webhooks, webhook_id, webhook_token) + Query(params2), requestOptions, params1); 54 | 55 | export const ExecuteSlack = (webhook_id: string, webhook_token: string, params?: { 56 | thread_id?: string; 57 | wait?: boolean; 58 | }, requestOptions?: RequestOptions) => 59 | Request(METHODS.POST, Path(PATHS.webhooks, webhook_id, webhook_token, PATHS.slack) + Query(params), requestOptions); 60 | 61 | export const ExecuteGitHub = (webhook_id: string, webhook_token: string, params?: { 62 | thread_id?: string; 63 | wait?: boolean; 64 | }, requestOptions?: RequestOptions) => 65 | Request(METHODS.POST, Path(PATHS.webhooks, webhook_id, webhook_token, PATHS.github) + Query(params), requestOptions); 66 | 67 | export const GetMessage = (webhook_id: string, webhook_token: string, message_id: string, params?: { 68 | thread_id?: string; 69 | }, requestOptions?: RequestOptions) => 70 | Request(METHODS.GET, Path(PATHS.webhooks, webhook_id, webhook_token, PATHS.messages, message_id) + Query(params), requestOptions); 71 | 72 | export const EditMessage = (webhook_id: string, webhook_token: string, message_id: string, params1: { 73 | content?: string; 74 | embeds?: types.Embed[]; 75 | allowed_mentions?: types.AllowedMentions; 76 | components?: types.ActionRow[]; 77 | attachments?: types.Attachment[]; 78 | }, params2?: { 79 | thread_id?: string; 80 | }, requestOptions?: RequestOptions) => 81 | Request(METHODS.PATCH, Path(PATHS.webhooks, webhook_id, webhook_token, PATHS.messages, message_id) + Query(params2), requestOptions, params1); 82 | 83 | export const DeleteMessage = (webhook_id: string, webhook_token: string, message_id: string, params?: { 84 | thread_id?: string; 85 | }, requestOptions?: RequestOptions) => 86 | Request(METHODS.DELETE, Path(PATHS.webhooks, webhook_id, webhook_token, PATHS.messages, message_id) + Query(params), requestOptions); 87 | -------------------------------------------------------------------------------- /src/actions/channel.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path, Query } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as helpers from '../helpers'; 4 | import type * as types from '../types'; 5 | 6 | export const Create = (guild_id: string, params: { 7 | name: string; 8 | type: T; 9 | position?: number; 10 | permission_overwrites?: types.PermissionsOverwrite[]; 11 | } & ({ 12 | type: types.GuildTextChannel['type']; 13 | topic?: string; 14 | rate_limit_per_user?: number; 15 | parent_id?: string; 16 | nsfw?: boolean; 17 | default_auto_archive_duration?: helpers.ThreadArchiveDurations; 18 | } | { 19 | type: types.GuildCategory['type']; 20 | } | { 21 | type: types.GuildVoiceChannel['type']; 22 | bitrate?: number; 23 | user_limit?: number; 24 | parent_id?: string; 25 | rtc_region?: string; 26 | video_quality_mode?: helpers.VideoQualityModes; 27 | }), requestOptions?: RequestOptions) => 28 | Request(METHODS.POST, Path(PATHS.guilds, guild_id, PATHS.channels), requestOptions, params); 31 | 32 | export const Get = (channel_id: string, requestOptions?: RequestOptions) => 33 | Request(METHODS.GET, Path(PATHS.channels, channel_id), requestOptions); 34 | 35 | export const Modify = (id: string, params: { 36 | name?: string; 37 | position?: number | null; 38 | permission_overwrites?: types.PermissionsOverwrite[] | null; 39 | } & ((T extends types.GuildTextChannel ? { 40 | type?: types.GuildTextChannel['type']; 41 | topic?: string | null; 42 | nsfw?: boolean | null; 43 | rate_limit_per_user?: number | null; 44 | parent_id?: string | null; 45 | default_auto_archive_duration?: helpers.ThreadArchiveDurations | null; 46 | } : never) | (T extends types.GuildVoiceChannel ? { 47 | bitrate?: number | null; 48 | user_limit?: number | null; 49 | parent_id?: string | null; 50 | rtc_region?: string | null; 51 | video_quality_mode?: helpers.VideoQualityModes; 52 | } : never)), requestOptions?: RequestOptions) => 53 | Request(METHODS.PATCH, Path(PATHS.channels, id), requestOptions, params); 54 | 55 | export const Delete = (channel_id: string, requestOptions?: RequestOptions) => 56 | Request(METHODS.DELETE, Path(PATHS.channels, channel_id), requestOptions); 57 | 58 | export const GetMessages = (channel_id: string, params?: { 59 | limit?: number; 60 | } & ({ 61 | around?: string; 62 | before?: undefined; 63 | after?: undefined; 64 | } | { 65 | around?: undefined; 66 | before?: string; 67 | after?: undefined; 68 | } | { 69 | around?: undefined; 70 | before?: undefined; 71 | after?: string; 72 | }), requestOptions?: RequestOptions) => 73 | Request(METHODS.GET, Path(PATHS.channels, channel_id, PATHS.messages) + Query(params), requestOptions); 74 | 75 | export const BulkDeleteMessages = (channel_id: string, params: { 76 | messages: string[]; 77 | }, requestOptions?: RequestOptions) => 78 | Request(METHODS.POST, Path(PATHS.channels, channel_id, PATHS.messages, PATHS.bulk_delete), requestOptions, params); 79 | 80 | export const EditPermissions = (channel_id: string, overwrite_id: string, params: { 81 | allow?: string | null; 82 | deny?: string | null; 83 | type: helpers.PermissionsOverwriteTypes; 84 | }, requestOptions?: RequestOptions) => 85 | Request(METHODS.PUT, Path(PATHS.channels, channel_id, PATHS.permissions, overwrite_id), requestOptions, params); 86 | 87 | export const GetInvites = (channel_id: string, requestOptions?: RequestOptions) => 88 | Request<(types.Invite & types.InviteMetadata)[]>(METHODS.GET, Path(PATHS.channels, channel_id, PATHS.invites), requestOptions); 89 | 90 | export const DeletePermission = (channel_id: string, overwrite_id: string, requestOptions?: RequestOptions) => 91 | Request(METHODS.DELETE, Path(PATHS.channels, channel_id, PATHS.permissions, overwrite_id), requestOptions); 92 | 93 | export const FollowNews = (channel_id: string, params: { 94 | webhook_channel_id: string; 95 | }, requestOptions?: RequestOptions) => 96 | Request(METHODS.POST, Path(PATHS.channels, channel_id, PATHS.followers), requestOptions, params); 97 | 98 | export const TriggerTypingIndicator = (channel_id: string, requestOptions?: RequestOptions) => 99 | Request(METHODS.POST, Path(PATHS.channels, channel_id, PATHS.typing), requestOptions); 100 | 101 | export const GetPinnedMessages = (channel_id: string, requestOptions?: RequestOptions) => 102 | Request(METHODS.GET, Path(PATHS.channels, channel_id, PATHS.pins), requestOptions); 103 | 104 | export const GetWebhooks = (channel_id: string, requestOptions?: RequestOptions) => 105 | Request(METHODS.GET, Path(PATHS.channels, channel_id, PATHS.webhooks), requestOptions); 106 | 107 | export const ListPublicArchivedThreads = (channel_id: string, params?: { 108 | before?: string; 109 | limit?: number; 110 | }, requestOptions?: RequestOptions) => 111 | Request<{ 112 | threads: types.Thread[]; 113 | members: types.ThreadMember[]; 114 | has_more: boolean; 115 | }>(METHODS.GET, Path(PATHS.channels, channel_id, PATHS.threads, PATHS.archived, PATHS.public) + Query(params), requestOptions); 116 | 117 | export const ListPrivateArchivedThreads = (channel_id: string, params?: { 118 | before?: string; 119 | limit?: number; 120 | }, requestOptions?: RequestOptions) => 121 | Request<{ 122 | threads: types.Thread[]; 123 | members: types.ThreadMember[]; 124 | has_more: boolean; 125 | }>(METHODS.GET, Path(PATHS.channels, channel_id, PATHS.threads, PATHS.archived, PATHS.private) + Query(params), requestOptions); 126 | 127 | export const ListJoinedPrivateArchivedThreads = (channel_id: string, params?: { 128 | before?: string; 129 | limit?: number; 130 | }, requestOptions?: RequestOptions) => 131 | Request<{ 132 | threads: types.Thread[]; 133 | members: types.ThreadMember[]; 134 | has_more: boolean; 135 | }>(METHODS.GET, Path(PATHS.channels, channel_id, PATHS.users, PATHS.me, PATHS.threads, PATHS.archived, PATHS.private) + Query(params), requestOptions); 136 | -------------------------------------------------------------------------------- /package/README.md: -------------------------------------------------------------------------------- 1 | # Discord Slim 2 | 3 | Lightweight **Discord API** library for **Node.js**. 4 | Provides pure API interaction via type definitions and some helper tools, without excessive abstractions. 5 | 6 | ## Before you start 7 | ### **Node.js** 14+ is required! 8 | Make sure you have some understaning of **[Discord API](https://discordapp.com/developers/docs)**. 9 | 10 | ## Docs 11 | 12 | ### Main exports 13 | **Client** - client for connecting to the Discord API gateway. 14 | **ClientEvents** - set of possible client events. 15 | **Authorization** - authorization class for client and actions. 16 | **Events** - set of possible gateway API events. 17 | **Actions** - access to API requests. 18 | **Helpers** - objects and constants for API. 19 | **Tools** - additional tools for convinience. 20 | **Voice** - client for connecting to voice channels. 21 | **VoiceEvents** - set of possible voice client events. 22 | **Types** - type definitions export for TypeScript. 23 | 24 | **TODO.** 25 | For now use e.g. VS Code for types completion. 26 | 27 | ## Installation 28 | ```sh 29 | npm i discord-slim 30 | ``` 31 | 32 | ## Usage example 33 | ### Initial setup 34 | ```js 35 | import { Client, ClientEvents, Authorization, Events, Actions, Helpers, Tools } from 'discord-slim'; 36 | 37 | // Basic setup to control client operation. 38 | // You probably want to use such code for every bot. 39 | 40 | const client = new Client(); 41 | client.on(ClientEvents.CONNECT, () => console.log('Connection established.')); 42 | client.on(ClientEvents.DISCONNECT, (code) => console.error(`Disconnect. (${code})`)); 43 | client.on(ClientEvents.INFO, console.log); 44 | client.on(ClientEvents.WARN, console.warn); 45 | client.on(ClientEvents.ERROR, console.error); 46 | client.on(ClientEvents.FATAL, (e) => { console.error(e); process.exit(1); }); 47 | 48 | // Authorization object. Required for client and actions. 49 | const authorization = new Authorization('token'); 50 | 51 | // Request options for actions. 52 | // By design every action can use its own options. 53 | // But for convinience you can set default options globally for all actions. 54 | // Default options can be overridden by passing `requestOptions` argument. 55 | 56 | Actions.setDefaultRequestOptions({ 57 | 58 | // Include authorization, it is required for most actions. 59 | authorization, 60 | 61 | // Rate limit behavior configuration. 62 | // This options is not required, but you probably want to care about the rate limit. 63 | rateLimit: { 64 | 65 | // Set how many attempts to make due to the rate limit. Default: 5. 66 | // This includes the first try, so values 1 and below will be treated as "no retries". 67 | retryCount: 5, 68 | 69 | // Rate limit hit callback. 70 | callback: (response, attempts) => 71 | console.log(`${response.message} Global: ${response.global}. Cooldown: ${response.retry_after} sec. Attempt: ${attempts}.`), 72 | 73 | }, 74 | 75 | }); 76 | 77 | ... 78 | 79 | // Start the client connection. 80 | client.Connect(authorization, Helpers.Intents.GUILDS | Helpers.Intents.GUILD_MESSAGES); 81 | ``` 82 | You can read about intents [here](https://discordapp.com/developers/docs/topics/gateway#gateway-intents). 83 | 84 | ### Basic message response 85 | ```js 86 | client.events.on(Events.MESSAGE_CREATE, (message) => { 87 | 88 | // Filter out any bot messages. 89 | if(message.author.bot) return; 90 | 91 | // Check that the message contains "hello" word. 92 | if(message.content.search(/(^|\s)hello($|\s)/i) < 0) return; 93 | 94 | // Using both reply and mention just for demo. 95 | Actions.Message.Create(message.channel_id, { 96 | content: `Hi, ${Tools.Mention.User(message.author)}!`, 97 | message_reference: { 98 | channel_id: message.channel_id, 99 | message_id: message.id, 100 | }, 101 | }); 102 | 103 | }); 104 | ``` 105 | 106 | ### Set bot status 107 | ```js 108 | client.events.on(Events.READY, () => { 109 | 110 | client.UpdatePresence({ 111 | status: Helpers.StatusTypes.ONLINE, 112 | activities: [{ type: Helpers.ActivityTypes.WATCHING, name: 'YOU' }], 113 | afk: false, 114 | since: 0, 115 | }); 116 | 117 | }); 118 | ``` 119 | 120 | ### Async capabilities 121 | ```js 122 | client.events.on(Events.READY, async (data) => { 123 | 124 | // Log all the global application commands. 125 | console.log(await Actions.Application.GetGlobalCommands(data.user.id)); 126 | 127 | }); 128 | ``` 129 | 130 | ### Using application commands 131 | Note: application commands require `applications.commands` scope. Read details in [docs](https://discord.com/developers/docs/interactions/application-commands#authorizing-your-application). 132 | ```js 133 | client.events.on(Events.GUILD_CREATE, (guild) => { 134 | 135 | // Create a command in your guild(s). 136 | // This example represents a simple command that just echoing the text back. 137 | Actions.Application.CreateGuildCommand('bot_id_here', guild.id, { 138 | type: Helpers.ApplicationCommandTypes.CHAT_INPUT, 139 | name: 'echo', 140 | description: 'Test application command.', 141 | options: [ 142 | { 143 | type: Helpers.ApplicationCommandOptionTypes.STRING, 144 | name: 'text', 145 | description: 'Echo message text.', 146 | required: true, 147 | }, 148 | ], 149 | }); 150 | 151 | }); 152 | 153 | // Respond to interaction event. 154 | client.events.on(Events.INTERACTION_CREATE, (interaction) => { 155 | 156 | // Check that the interaction is an application command 157 | if(interaction.type != Helpers.InteractionTypes.APPLICATION_COMMAND) return; 158 | 159 | // Check that the command is a chat command 160 | const data = interaction.data; 161 | if(data?.type != Helpers.ApplicationCommandTypes.CHAT_INPUT) return; 162 | 163 | // Check the command by name. 164 | if(data.name != 'echo') return; 165 | 166 | // Check the data type. 167 | const option = data.options?.[0]; 168 | if(option?.type != Helpers.ApplicationCommandOptionTypes.STRING) return; 169 | 170 | // Make a response. 171 | Actions.Application.CreateInteractionResponse(interaction.id, interaction.token, { 172 | type: Helpers.InteractionCallbackTypes.CHANNEL_MESSAGE_WITH_SOURCE, 173 | data: { 174 | 175 | // Just echoing the content. 176 | content: option.value, 177 | 178 | // "EPHEMERAL" flag means that the response will be visible only by the caller. 179 | flags: Helpers.MessageFlags.EPHEMERAL, 180 | 181 | }, 182 | }); 183 | 184 | }); 185 | ``` 186 | -------------------------------------------------------------------------------- /src/voice.ts: -------------------------------------------------------------------------------- 1 | import { WebSocket, RawData } from 'ws'; 2 | import { EventEmitter } from 'events'; 3 | import { SafeJsonParse } from './_common'; 4 | import { VoiceEncryptionModes, SpeakingStates } from './helpers'; 5 | 6 | const enum OPCodes { 7 | IDENTIFY = 0, 8 | SELECT_PROTOCOL = 1, 9 | READY = 2, 10 | HEARTBEAT = 3, 11 | SESSION_DESCRIPTION = 4, 12 | SPEAKING = 5, 13 | HEARTBEAT_ACK = 6, 14 | RESUME = 7, 15 | HELLO = 8, 16 | RESUMED = 9, 17 | CLIENT_DISCONNECT = 13, 18 | } 19 | 20 | type Broadcast = { 21 | ssrc: number; 22 | ip: string; 23 | port: number; 24 | }; 25 | 26 | type Session = { 27 | secret_key: number[]; 28 | }; 29 | 30 | type PacketTypes = { 31 | [OPCodes.HELLO]: { 32 | heartbeat_interval: number; 33 | }; 34 | [OPCodes.READY]: Broadcast; 35 | [OPCodes.SESSION_DESCRIPTION]: Session; 36 | [OPCodes.HEARTBEAT_ACK]: {}; 37 | }; 38 | 39 | type Packet = { op: T; } & PacketTypes[T]; 40 | 41 | type PacketHandlers = { 42 | [T in keyof PacketTypes]?: (data: Packet) => void; 43 | }; 44 | 45 | const 46 | VOICE_VERSION = 4, 47 | FATAL_CODES = Object.freeze([4002, 4004, 4006, 4011, 4014]), 48 | DROP_CODES = Object.freeze([4009]), 49 | RECONNECT_TIMEOUT = 5000; 50 | 51 | export class Voice extends EventEmitter { 52 | private _ws?: WebSocket; 53 | private _options?: { 54 | server_id: string; 55 | user_id: string; 56 | session_id: string; 57 | token: string; 58 | }; 59 | private _endpoint?: string; 60 | private _encryption?: string; 61 | private _resume = false; 62 | private _lastHeartbeatAck = false; 63 | private _heartbeatTimer?: NodeJS.Timer; 64 | private _broadcast?: Broadcast; 65 | private _ssrc?: number; 66 | 67 | constructor() { 68 | super(); 69 | } 70 | 71 | private _wsConnect = async (resume?: boolean) => { 72 | this._wsDisconnect(); 73 | this._resume = Boolean(resume); 74 | 75 | if(this._ws) 76 | return this.emit(VoiceEvents.WARN, 'The voice client is already connected.'); 77 | 78 | try { 79 | this._ws = new WebSocket(`wss://${this._endpoint}?v=${VOICE_VERSION}`); 80 | } catch { 81 | return this.emit(VoiceEvents.FATAL, 'Unable to create a socket.'); 82 | } 83 | 84 | this._ws.on('message', this._onMessage); 85 | this._ws.on('close', this._onClose); 86 | this._ws.on('error', this._onError); 87 | }; 88 | 89 | private _wsDisconnect = (code = 1012) => { 90 | const ws = this._ws; 91 | if(!ws) return; 92 | this._setHeartbeatTimer(); 93 | this.emit(VoiceEvents.DISCONNECT, code); 94 | this._ws = undefined; 95 | ws.removeAllListeners(); 96 | ws.close(code); 97 | }; 98 | 99 | private _send = (op: OPCodes, d: any) => 100 | this._ws?.send(JSON.stringify({ op, d })); 101 | 102 | private _packetHandlers: PacketHandlers = { 103 | [OPCodes.HELLO]: ({ heartbeat_interval }) => { 104 | this._send( 105 | this._resume ? 106 | OPCodes.RESUME : OPCodes.IDENTIFY, 107 | this._options, 108 | ); 109 | this._resume = true; 110 | this._lastHeartbeatAck = true; 111 | this._setHeartbeatTimer(heartbeat_interval); 112 | this._sendHeartbeat(); 113 | }, 114 | 115 | [OPCodes.READY]: ({ ssrc, ip, port }) => { 116 | this._broadcast = { ssrc, ip, port }; 117 | this._send(OPCodes.SELECT_PROTOCOL, { 118 | protocol: 'udp', 119 | data: { 120 | address: ip, 121 | port, 122 | mode: this._encryption, 123 | }, 124 | }); 125 | }, 126 | 127 | [OPCodes.SESSION_DESCRIPTION]: ({ secret_key }) => { 128 | this.emit(VoiceEvents.CONNECT, { 129 | ...this._broadcast, 130 | secret_key, 131 | }); 132 | }, 133 | 134 | [OPCodes.HEARTBEAT_ACK]: () => 135 | this._lastHeartbeatAck = true, 136 | }; 137 | 138 | private _onMessage = (data: RawData) => { 139 | const packet = SafeJsonParse>(String(data)); 140 | if(!packet) return; 141 | this._packetHandlers[packet.op]?.(packet); 142 | }; 143 | 144 | private _sendHeartbeat = () => { 145 | if(this._ws?.readyState != 1) return; 146 | if(!this._lastHeartbeatAck) { 147 | this.emit(VoiceEvents.WARN, 'Heartbeat timeout.'); 148 | this._wsConnect(true); 149 | return; 150 | } 151 | this._lastHeartbeatAck = false; 152 | this._send(OPCodes.HEARTBEAT, null); 153 | }; 154 | 155 | private _setHeartbeatTimer = (interval?: number) => { 156 | this._heartbeatTimer && clearInterval(this._heartbeatTimer); 157 | this._heartbeatTimer = interval ? 158 | setInterval(this._sendHeartbeat, interval) : undefined; 159 | }; 160 | 161 | private _onClose = (code: number) => { 162 | this._wsDisconnect(code); 163 | FATAL_CODES.includes(code) ? 164 | this.emit(VoiceEvents.FATAL, `Fatal error. Code: ${code}`) : 165 | setTimeout(this._wsConnect, RECONNECT_TIMEOUT, !DROP_CODES.includes(code)); 166 | }; 167 | 168 | private _onError = (error: Error) => 169 | this.emit(VoiceEvents.ERROR, error); 170 | 171 | Connect = ( 172 | server_id: string, 173 | user_id: string, 174 | session_id: string, 175 | token: string, 176 | endpoint: string, 177 | encryption: VoiceEncryptionModes, 178 | ) => { 179 | this._options = { token, server_id, user_id, session_id }; 180 | this._endpoint = endpoint; 181 | this._encryption = encryption; 182 | this._wsConnect(); 183 | }; 184 | 185 | Disconnect = (code?: number) => 186 | this._wsDisconnect(code); 187 | 188 | SetSpeakingState = (speaking: SpeakingStates, delay = 0) => { 189 | if(!this._ws) throw 'No connection.'; 190 | this._send(OPCodes.SPEAKING, { 191 | speaking, 192 | delay, 193 | ssrc: this._ssrc, 194 | }); 195 | }; 196 | } 197 | 198 | export enum VoiceEvents { 199 | CONNECT = 'connect', 200 | DISCONNECT = 'disconnect', 201 | WARN = 'warn', 202 | ERROR = 'error', 203 | FATAL = 'fatal', 204 | } 205 | 206 | type VoiceEventTypes = { 207 | [VoiceEvents.CONNECT]: Broadcast & Session; 208 | [VoiceEvents.DISCONNECT]: number; 209 | [VoiceEvents.WARN]: string; 210 | [VoiceEvents.ERROR]: Error; 211 | [VoiceEvents.FATAL]: string; 212 | }; 213 | 214 | export interface Voice extends EventEmitter { 215 | on(event: E, callback: (data: VoiceEventTypes[E]) => void): this; 216 | once(event: E, callback: (data: VoiceEventTypes[E]) => void): this; 217 | off(event: E, callback: (data: VoiceEventTypes[E]) => void): this; 218 | } 219 | -------------------------------------------------------------------------------- /src/actions/guild.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path, Query } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as helpers from '../helpers'; 4 | import type * as types from '../types'; 5 | 6 | export const GetAuditLog = (guild_id: string, params?: { 7 | user_id?: string; 8 | action_type?: number; 9 | before?: string; 10 | limit?: number; 11 | }, requestOptions?: RequestOptions) => 12 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.auditLogs) + Query(params), requestOptions); 13 | 14 | export const ListEmojis = (guild_id: string, requestOptions?: RequestOptions) => 15 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.emojis), requestOptions); 16 | 17 | export const Create = (params: { 18 | name: string; 19 | icon?: string; 20 | verification_level?: helpers.VerificationLevels; 21 | default_message_notifications?: helpers.DefaultMessageNotificationLevels; 22 | explicit_content_filter?: helpers.ExplicitContentFilterLevels; 23 | roles?: types.Role[]; 24 | channels?: types.GuildChannel[]; 25 | afk_channel_id?: string; 26 | afk_timeout?: number; 27 | system_channel_id?: string; 28 | system_channel_flags?: helpers.SystemChannelFlags; 29 | }, requestOptions?: RequestOptions) => 30 | Request(METHODS.POST, PATHS.guilds, requestOptions, params); 31 | 32 | export const Get = (guild_id: string, params?: { 33 | with_counts?: boolean; 34 | }, requestOptions?: RequestOptions) => 35 | Request(METHODS.GET, Path(PATHS.guilds, guild_id) + Query(params), requestOptions); 36 | 37 | export const GetPreview = (guild_id: string, requestOptions?: RequestOptions) => 38 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.preview), requestOptions); 39 | 40 | export const Modify = (guild_id: string, params: { 41 | name?: string; 42 | verification_level?: helpers.VerificationLevels; 43 | default_message_notifications?: helpers.DefaultMessageNotificationLevels; 44 | explicit_content_filter?: helpers.ExplicitContentFilterLevels; 45 | afk_channel_id?: string | null; 46 | afk_timeout?: number; 47 | icon?: string | null; 48 | owner_id?: string; 49 | splash?: string | null; 50 | discovery_splash?: string | null; 51 | banner?: string | null; 52 | system_channel_id?: string | null; 53 | system_channel_flags?: helpers.SystemChannelFlags; 54 | rules_channel_id?: string | null; 55 | public_updates_channel_id?: string | null; 56 | preferred_locale?: string | null; 57 | features?: helpers.GuildFeatures[]; 58 | description?: string | null; 59 | premium_progress_bar_enabled?: boolean; 60 | }, requestOptions?: RequestOptions) => 61 | Request(METHODS.PATCH, Path(PATHS.guilds, guild_id), requestOptions, params); 62 | 63 | export const Delete = (guild_id: string, requestOptions?: RequestOptions) => 64 | Request(METHODS.DELETE, Path(PATHS.guilds, guild_id), requestOptions); 65 | 66 | export const GetChannels = (guild_id: string, requestOptions?: RequestOptions) => 67 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.channels), requestOptions); 68 | 69 | export const ModifyChannelPositions = (guild_id: string, params: ({ 70 | id: string; 71 | position: number | null; 72 | })[], requestOptions?: RequestOptions) => 73 | Request(METHODS.PATCH, Path(PATHS.guilds, guild_id, PATHS.channels), requestOptions, params); 74 | 75 | export const ListActiveThreads = (guild_id: string, requestOptions?: RequestOptions) => 76 | Request<{ 77 | threads: types.Thread[]; 78 | members: types.ThreadMember[]; 79 | }>(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.threads, PATHS.active), requestOptions); 80 | 81 | export const ListMembers = (guild_id: string, params?: { 82 | limit?: number; 83 | after?: string; 84 | }, requestOptions?: RequestOptions) => 85 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.members) + Query(params), requestOptions); 86 | 87 | export const SearchMembers = (guild_id: string, params: { 88 | query: number; 89 | limit?: number; 90 | }, requestOptions?: RequestOptions) => 91 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.members, PATHS.search) + Query(params), requestOptions); 92 | 93 | export const GetBans = (guild_id: string, params?: { 94 | limit?: number; 95 | } & ({ 96 | before?: string; 97 | after?: undefined; 98 | } | { 99 | before?: undefined; 100 | after?: string; 101 | }), requestOptions?: RequestOptions) => 102 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.bans) + Query(params), requestOptions); 103 | 104 | export const GetRoles = (guild_id: string, requestOptions?: RequestOptions) => 105 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.roles), requestOptions); 106 | 107 | export const ModifyRolePositions = (guild_id: string, params: ({ 108 | id: string; 109 | position?: number | null; 110 | })[], requestOptions?: RequestOptions) => 111 | Request(METHODS.PATCH, Path(PATHS.guilds, guild_id, PATHS.roles), requestOptions, params); 112 | 113 | export const GetPruneCount = (guild_id: string, params?: { 114 | days?: number; 115 | include_roles?: string; 116 | }, requestOptions?: RequestOptions) => 117 | Request<{ pruned: number; }>(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.prune) + Query(params), requestOptions); 118 | 119 | export const Prune = (guild_id: string, params?: { 120 | days?: number; 121 | compute_prune_count?: boolean; 122 | include_roles?: string; 123 | }, requestOptions?: RequestOptions) => 124 | Request<{ pruned: number | null; }>(METHODS.POST, Path(PATHS.guilds, guild_id, PATHS.prune), requestOptions, params); 125 | 126 | export const GetVoiceRegions = (guild_id: string, requestOptions?: RequestOptions) => 127 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.regions), requestOptions); 128 | 129 | export const GetInvites = (guild_id: string, requestOptions?: RequestOptions) => 130 | Request<(types.Invite & types.InviteMetadata)[]>(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.invites), requestOptions); 131 | 132 | export const GetIntegrations = (guild_id: string, requestOptions?: RequestOptions) => 133 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.integrations), requestOptions); 134 | 135 | export const DeleteIntegration = (guild_id: string, integration_id: string, requestOptions?: RequestOptions) => 136 | Request(METHODS.DELETE, Path(PATHS.guilds, guild_id, PATHS.integrations, integration_id), requestOptions); 137 | 138 | export const GetVanityURL = (guild_id: string, requestOptions?: RequestOptions) => 139 | Request<{ code: string; uses: number; }>(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.vanity_url), requestOptions); 140 | 141 | export const CreateFromTemplate = (template_code: string, params: { 142 | name: string; 143 | icon?: string; 144 | }, requestOptions?: RequestOptions) => 145 | Request(METHODS.POST, Path(PATHS.guilds, PATHS.templates, template_code), requestOptions, params); 146 | 147 | export const GetTemplates = (guild_id: string, requestOptions?: RequestOptions) => 148 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.templates), requestOptions); 149 | 150 | export const GetWebhooks = (guild_id: string, requestOptions?: RequestOptions) => 151 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.webhooks), requestOptions); 152 | 153 | export const ListStickers = (guild_id: string, requestOptions?: RequestOptions) => 154 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.stickers), requestOptions); 155 | 156 | export const ListScheduledEvents = (guild_id: string, params?: { 157 | with_user_count?: boolean; 158 | }, requestOptions?: RequestOptions) => 159 | Request(METHODS.GET, Path(PATHS.guilds, guild_id, PATHS.scheduled_events) + Query(params), requestOptions); 160 | -------------------------------------------------------------------------------- /src/actions/application.ts: -------------------------------------------------------------------------------- 1 | import { METHODS, PATHS, Path, Query } from './_common'; 2 | import { Request, RequestOptions } from '../request'; 3 | import type * as helpers from '../helpers'; 4 | import type * as types from '../types'; 5 | 6 | export const GetGlobalCommands = (application_id: string, params?: { 7 | with_localizations?: boolean; 8 | }, requestOptions?: RequestOptions) => 9 | Request<(types.ApplicationCommand & { 10 | name_localized?: string; 11 | description_localized?: string; 12 | })[]>(METHODS.GET, Path(PATHS.applications, application_id, PATHS.commands) + Query(params), requestOptions); 13 | 14 | export const CreateGlobalCommand = (application_id: string, params: types.ApplicationCommandBase, requestOptions?: RequestOptions) => 15 | Request(METHODS.POST, Path(PATHS.applications, application_id, PATHS.commands), requestOptions, params); 16 | 17 | export const GetGlobalCommand = (application_id: string, command_id: string, requestOptions?: RequestOptions) => 18 | Request(METHODS.GET, Path(PATHS.applications, application_id, PATHS.commands, command_id), requestOptions); 19 | 20 | export const EditGlobalCommand = (application_id: string, command_id: string, params: Partial>, requestOptions?: RequestOptions) => 21 | Request(METHODS.PATCH, Path(PATHS.applications, application_id, PATHS.commands, command_id), requestOptions, params); 22 | 23 | export const DeleteGlobalCommand = (application_id: string, command_id: string, requestOptions?: RequestOptions) => 24 | Request(METHODS.DELETE, Path(PATHS.applications, application_id, PATHS.commands, command_id), requestOptions); 25 | 26 | export const GetGuildCommands = (application_id: string, guild_id: string, params?: { 27 | with_localizations?: boolean; 28 | }, requestOptions?: RequestOptions) => 29 | Request<(types.ApplicationCommand & { 30 | name_localized?: string; 31 | description_localized?: string; 32 | dm_permission?: undefined; 33 | })[]>(METHODS.GET, Path(PATHS.applications, application_id, PATHS.guilds, guild_id, PATHS.commands) + Query(params), requestOptions); 34 | 35 | export const BulkOverwriteGlobalCommands = (application_id: string, params: types.ApplicationCommandBase[], requestOptions?: RequestOptions) => 36 | Request(METHODS.PUT, Path(PATHS.applications, application_id, PATHS.commands), requestOptions, params); 37 | 38 | export const CreateGuildCommand = (application_id: string, guild_id: string, params: types.ApplicationCommandBase & { 39 | dm_permission?: undefined; 40 | }, requestOptions?: RequestOptions) => 41 | Request(METHODS.POST, Path(PATHS.applications, application_id, PATHS.guilds, guild_id, PATHS.commands), requestOptions, params); 42 | 43 | export const GetGuildCommand = (application_id: string, guild_id: string, command_id: string, requestOptions?: RequestOptions) => 44 | Request(METHODS.GET, Path(PATHS.applications, application_id, PATHS.guilds, guild_id, PATHS.commands, command_id), requestOptions); 47 | 48 | export const EditGuildCommand = (application_id: string, guild_id: string, command_id: string, params: Partial>, requestOptions?: RequestOptions) => 52 | Request(METHODS.PATCH, Path(PATHS.applications, application_id, PATHS.guilds, guild_id, PATHS.commands, command_id), requestOptions, params); 55 | 56 | export const DeleteGuildCommand = (application_id: string, guild_id: string, command_id: string, requestOptions?: RequestOptions) => 57 | Request(METHODS.DELETE, Path(PATHS.applications, application_id, PATHS.guilds, guild_id, PATHS.commands, command_id), requestOptions); 58 | 59 | export const BulkOverwriteGuildCommands = (application_id: string, guild_id: string, params: (types.ApplicationCommandBase & { 60 | dm_permission?: undefined; 61 | })[], requestOptions?: RequestOptions) => 62 | Request<(types.ApplicationCommand & { 63 | dm_permission?: undefined; 64 | })[]>(METHODS.PUT, Path(PATHS.applications, application_id, PATHS.guilds, guild_id, PATHS.commands), requestOptions, params); 65 | 66 | export const GetGuildCommandPermissions = (application_id: string, guild_id: string, requestOptions?: RequestOptions) => 67 | Request(METHODS.GET, Path(PATHS.applications, application_id, PATHS.guilds, guild_id, PATHS.commands, PATHS.permissions), requestOptions); 68 | 69 | export const GetCommandPermissions = (application_id: string, guild_id: string, command_id: string, requestOptions?: RequestOptions) => 70 | Request(METHODS.GET, Path(PATHS.applications, application_id, PATHS.guilds, guild_id, PATHS.commands, command_id, PATHS.permissions), requestOptions); 71 | 72 | export const EditCommandPermissions = (application_id: string, guild_id: string, command_id: string, params: { 73 | permissions: types.ApplicationCommandPermissions[]; 74 | }, requestOptions?: RequestOptions) => 75 | Request(METHODS.PUT, Path(PATHS.applications, application_id, PATHS.guilds, guild_id, PATHS.commands, command_id, PATHS.permissions), requestOptions, params); 76 | 77 | export const CreateInteractionResponse = (interaction_id: string, interaction_token: string, params: types.InteractionResponse, requestOptions?: RequestOptions) => 78 | Request(METHODS.POST, Path(PATHS.interactions, interaction_id, interaction_token, PATHS.callback), requestOptions, params); 79 | 80 | export const GetOriginalInteractionResponse = (application_id: string, interaction_token: string, requestOptions?: RequestOptions) => 81 | Request(METHODS.GET, Path(PATHS.webhooks, application_id, interaction_token, PATHS.messages, PATHS.original), requestOptions); 82 | 83 | export const EditOriginalInteractionResponse = (application_id: string, interaction_token: string, params: { 84 | content?: string; 85 | embeds?: types.Embed[]; 86 | allowed_mentions?: types.AllowedMentions; 87 | components?: types.ActionRow[]; 88 | }, requestOptions?: RequestOptions) => 89 | Request(METHODS.PATCH, Path(PATHS.webhooks, application_id, interaction_token, PATHS.messages, PATHS.original), requestOptions, params); 90 | 91 | export const DeleteOriginalInteractionResponse = (application_id: string, interaction_token: string, requestOptions?: RequestOptions) => 92 | Request(METHODS.DELETE, Path(PATHS.webhooks, application_id, interaction_token, PATHS.messages, PATHS.original), requestOptions); 93 | 94 | export const CreateFollowupMessage = (application_id: string, interaction_token: string, params: { 95 | content?: string; 96 | username?: string; 97 | avatar_url?: string; 98 | tts?: string; 99 | embeds?: types.Embed[]; 100 | allowed_mentions?: types.AllowedMentions; 101 | flags?: helpers.MessageFlags; 102 | components?: types.ActionRow[]; 103 | }, requestOptions?: RequestOptions) => 104 | Request(METHODS.POST, Path(PATHS.webhooks, application_id, interaction_token), requestOptions, params); 105 | 106 | export const GetFollowupMessage = (application_id: string, interaction_token: string, message_id: string, requestOptions?: RequestOptions) => 107 | Request(METHODS.GET, Path(PATHS.webhooks, application_id, interaction_token, PATHS.messages, message_id), requestOptions); 108 | 109 | export const EditFollowupMessage = (application_id: string, interaction_token: string, message_id: string, params: { 110 | content?: string; 111 | embeds?: types.Embed[]; 112 | allowed_mentions?: types.AllowedMentions; 113 | components?: types.ActionRow[]; 114 | }, requestOptions?: RequestOptions) => 115 | Request(METHODS.PATCH, Path(PATHS.webhooks, application_id, interaction_token, PATHS.messages, message_id), requestOptions, params); 116 | 117 | export const DeleteFollowupMessage = (application_id: string, interaction_token: string, message_id: string, requestOptions?: RequestOptions) => 118 | Request(METHODS.DELETE, Path(PATHS.webhooks, application_id, interaction_token, PATHS.messages, message_id), requestOptions); 119 | -------------------------------------------------------------------------------- /src/tools.ts: -------------------------------------------------------------------------------- 1 | import * as helpers from './helpers'; 2 | import type * as types from './types'; 3 | 4 | type PermissionLike = string | number | bigint | PermissionSet; 5 | 6 | const EPV = (p: PermissionLike) => 7 | p instanceof PermissionSet ? p.value : BigInt(p); 8 | 9 | export class PermissionSet { 10 | private _value: bigint; 11 | 12 | constructor(value?: string | number | bigint) { 13 | this._value = value ? BigInt(value) : 0n; 14 | } 15 | 16 | get value() { return this._value; } 17 | 18 | toString = () => String(this._value); 19 | toJSON = () => String(this._value); 20 | valueOf = () => this._value; 21 | 22 | clone = () => new PermissionSet(this._value); 23 | 24 | equals = (permissions: PermissionLike) => 25 | this._value == EPV(permissions); 26 | 27 | combine = (permissions: PermissionLike | PermissionLike[]) => { 28 | if(Array.isArray(permissions)) { 29 | let value = this._value; 30 | for(const p of permissions) 31 | value |= EPV(p); 32 | this._value = value; 33 | } else { 34 | this._value |= EPV(permissions); 35 | } 36 | }; 37 | 38 | check = (permission: helpers.Permission) => 39 | (this._value & permission) == permission; 40 | 41 | has = (permission: helpers.Permission) => 42 | this.check(helpers.Permissions.ADMINISTRATOR) || this.check(permission); 43 | 44 | add = (permission: helpers.Permission) => 45 | void (this._value |= permission); 46 | 47 | remove = (permission: helpers.Permission) => 48 | void (this._value &= ~permission); 49 | 50 | set = (permission: helpers.Permission, set: boolean) => 51 | void (set ? this.add : this.remove)(permission); 52 | 53 | toggle = (permission: helpers.Permission) => 54 | void this.set(permission, !this.has(permission)); 55 | } 56 | 57 | const EID = (value: { id: string; } | string) => 58 | (typeof value == 'object') ? value.id : value; 59 | 60 | export const Mention = { 61 | 62 | User: ( 63 | user: types.User | { id: string; } | string, 64 | ) => `<@${EID(user)}>`, 65 | 66 | Channel: ( 67 | channel: types.Channel | { id: string; } | string, 68 | ) => `<#${EID(channel)}>`, 69 | 70 | Role: ( 71 | role: types.Role | { id: string; } | string, 72 | ) => `<@&${EID(role)}>`, 73 | 74 | }; 75 | 76 | export const Format = { 77 | 78 | Emoji: ( 79 | emoji: types.Emoji | { name: string; id: string; animated?: boolean; }, 80 | ) => `<${emoji.animated ? 'a' : ''}:${emoji.name}:${emoji.id}>`, 81 | 82 | Reaction: ( 83 | emoji: types.Emoji | { name: string; id: string; } 84 | ) => `${emoji.name}:${emoji.id}`, 85 | 86 | Timestamp: ( 87 | timestamp: number | string | Date, 88 | style?: helpers.TimestampStyles, 89 | ) => { 90 | let value; 91 | 92 | if(timestamp instanceof Date) 93 | value = Math.trunc(timestamp.getTime() / 1000); 94 | else if(typeof timestamp == 'string') 95 | value = Math.trunc(new Date(timestamp).getTime() / 1000); 96 | else 97 | value = timestamp; 98 | 99 | return style ? 100 | `` : 101 | ``; 102 | }, 103 | 104 | }; 105 | 106 | export const Link = { 107 | 108 | Message: ( 109 | message: types.Message | { id: string; channel_id: string; guild_id?: string; }, 110 | ) => `${helpers.HOST}/channels/${message.guild_id ?? '@me'}/${message.channel_id}/${message.id}`, 111 | 112 | }; 113 | 114 | const SizeExtOpt = (size?: number, ext?: string) => 115 | (ext ? `.${ext}` : '') + (size ? `?size=${size}` : ''); 116 | 117 | export const Resource = { 118 | 119 | CustomEmoji: ( 120 | emoji: types.Emoji | { id?: string; }, 121 | size?: number, 122 | ext?: 'png' | 'jpg' | 'webp' | 'gif', 123 | ) => emoji.id ? 124 | `${helpers.CDN}/emojis/${emoji.id}${SizeExtOpt(size, ext)}` : null, 125 | 126 | GuildIcon: ( 127 | guild: types.Guild | { id: string; icon?: string; }, 128 | size?: number, 129 | ext?: 'png' | 'jpg' | 'webp' | 'gif', 130 | ) => guild.icon ? 131 | `${helpers.CDN}/icons/${guild.id}/${guild.icon}${SizeExtOpt(size, ext)}` : null, 132 | 133 | GuildSplash: ( 134 | guild: types.Guild | { id: string; splash?: string; }, 135 | size?: number, 136 | ext?: 'png' | 'jpg' | 'webp', 137 | ) => guild.splash ? 138 | `${helpers.CDN}/splashes/${guild.id}/${guild.splash}${SizeExtOpt(size, ext)}` : null, 139 | 140 | GuildDiscoverySplash: ( 141 | guild: types.Guild | { id: string; discovery_splash?: string; }, 142 | size?: number, 143 | ext?: 'png' | 'jpg' | 'webp', 144 | ) => guild.discovery_splash ? 145 | `${helpers.CDN}/discovery-splashes/${guild.id}/${guild.discovery_splash}${SizeExtOpt(size, ext)}` : null, 146 | 147 | GuildBanner: ( 148 | guild: types.Guild | { id: string; banner?: string; }, 149 | size?: number, 150 | ext?: 'png' | 'jpg' | 'webp' | 'gif', 151 | ) => guild.banner ? 152 | `${helpers.CDN}/banners/${guild.id}/${guild.banner}${SizeExtOpt(size, ext)}` : null, 153 | 154 | UserAvatar: ( 155 | user: types.User | { id: string; discriminator: string | number; avatar?: string; }, 156 | size?: number, 157 | ext?: 'png' | 'jpg' | 'webp' | 'gif', 158 | ) => user.avatar ? 159 | `${helpers.CDN}/avatars/${user.id}/${user.avatar}${SizeExtOpt(size, ext)}` : 160 | `${helpers.CDN}/embed/avatars/${Number(user.discriminator) % 5}.png`, 161 | 162 | UserBanner: ( 163 | user: types.User | { id: string; banner?: string; }, 164 | size?: number, 165 | ext?: 'png' | 'jpg' | 'webp' | 'gif', 166 | ) => user.banner ? 167 | `${helpers.CDN}/banners/${user.id}/${user.banner}${SizeExtOpt(size, ext)}` : null, 168 | 169 | ApplicationIcon: ( 170 | application: types.Application | { id: string; icon?: string; }, 171 | size?: number, 172 | ext?: 'png' | 'jpg' | 'webp', 173 | ) => application.icon ? 174 | `${helpers.CDN}/app-icons/${application.id}/${application.icon}${SizeExtOpt(size, ext)}` : null, 175 | 176 | ApplicationAsset: ( 177 | application: types.Application | { id: string; } | string, 178 | asset_id: string, 179 | size?: number, 180 | ext?: 'png' | 'jpg' | 'webp', 181 | ) => `${helpers.CDN}/app-assets/${EID(application)}/${asset_id}${SizeExtOpt(size, ext)}`, 182 | 183 | AchievementIcon: ( 184 | application: types.Application | { id: string; } | string, 185 | achievement_id: string | number | BigInt, 186 | icon_hash: string, 187 | size?: number, 188 | ext?: 'png' | 'jpg' | 'webp', 189 | ) => `${helpers.CDN}/app-assets/${EID(application)}/achievements/${achievement_id}/icons/${icon_hash}${SizeExtOpt(size, ext)}`, 190 | 191 | StickerPackBanner: ( 192 | application: types.Application | { id: string; } | string, 193 | sticker_pack: types.StickerPack | { banner_asset_id: string; }, 194 | size?: number, 195 | ext?: 'png' | 'jpg' | 'webp', 196 | ) => `${helpers.CDN}/app-assets/${EID(application)}/store/${sticker_pack.banner_asset_id}${SizeExtOpt(size, ext)}`, 197 | 198 | TeamIcon: ( 199 | team: types.Team | { id: string; icon?: string; }, 200 | size?: number, 201 | ext?: 'png' | 'jpg' | 'webp', 202 | ) => team.icon ? 203 | `${helpers.CDN}/team-icons/${team.id}/${team.icon}${SizeExtOpt(size, ext)}` : null, 204 | 205 | Sticker: ( 206 | sticker: types.Sticker | { id: string; format_type: helpers.MessageStickerFormatTypes; }, 207 | ) => `${helpers.CDN}/stickers/${EID(sticker)}.${(sticker.format_type == helpers.MessageStickerFormatTypes.LOTTIE) ? 'json' : 'png'}`, 208 | 209 | RoleIcon: ( 210 | role: types.Role | { id: string; icon: string; }, 211 | size?: number, 212 | ext?: 'png' | 'jpg' | 'webp', 213 | ) => role.icon ? 214 | `${helpers.CDN}/role-icons/${role.id}/${role.icon}${SizeExtOpt(size, ext)}` : null, 215 | 216 | GuildScheduledEventCover: ( 217 | event: types.ScheduledEvent | { id: string; image: string | null; }, 218 | size?: number, 219 | ext?: 'png' | 'jpg' | 'webp', 220 | ) => event.image ? 221 | `${helpers.CDN}/guild-events/${event.id}/${event.image}${SizeExtOpt(size, ext)}` : null, 222 | 223 | GuildMemberBanner: ( 224 | guild: types.Guild | { id: string; } | string, 225 | user: types.User | { id: string; } | string, 226 | banner: string, 227 | size?: number, 228 | ext?: 'png' | 'jpg' | 'webp' | 'gif', 229 | ) => `${helpers.CDN}/guilds/${EID(guild)}/users/${EID(user)}/banners/${banner}${SizeExtOpt(size, ext)}`, 230 | 231 | }; 232 | 233 | export const Utils = { 234 | 235 | GetUserCreationDate: (user: types.User | { id: string; } | string) => 236 | new Date(Number(BigInt(EID(user)) >> 22n) + 1420070400000), 237 | 238 | }; 239 | -------------------------------------------------------------------------------- /src/events.ts: -------------------------------------------------------------------------------- 1 | import type { EventEmitter } from 'events'; 2 | import type { InviteTargetTypes } from './helpers'; 3 | import type * as types from './types'; 4 | 5 | export enum Events { 6 | READY = 'READY', 7 | RESUMED = 'RESUMED', 8 | APPLICATION_COMMAND_PERMISSIONS_UPDATE = 'APPLICATION_COMMAND_PERMISSIONS_UPDATE', 9 | CHANNEL_CREATE = 'CHANNEL_CREATE', 10 | CHANNEL_UPDATE = 'CHANNEL_UPDATE', 11 | CHANNEL_DELETE = 'CHANNEL_DELETE', 12 | CHANNEL_PINS_UPDATE = 'CHANNEL_PINS_UPDATE', 13 | GUILD_CREATE = 'GUILD_CREATE', 14 | GUILD_UPDATE = 'GUILD_UPDATE', 15 | GUILD_DELETE = 'GUILD_DELETE', 16 | GUILD_BAN_ADD = 'GUILD_BAN_ADD', 17 | GUILD_BAN_REMOVE = 'GUILD_BAN_REMOVE', 18 | GUILD_EMOJIS_UPDATE = 'GUILD_EMOJIS_UPDATE', 19 | GUILD_INTEGRATIONS_UPDATE = 'GUILD_INTEGRATIONS_UPDATE', 20 | GUILD_MEMBER_ADD = 'GUILD_MEMBER_ADD', 21 | GUILD_MEMBER_REMOVE = 'GUILD_MEMBER_REMOVE', 22 | GUILD_MEMBER_UPDATE = 'GUILD_MEMBER_UPDATE', 23 | GUILD_MEMBERS_CHUNK = 'GUILD_MEMBERS_CHUNK', 24 | GUILD_ROLE_CREATE = 'GUILD_ROLE_CREATE', 25 | GUILD_ROLE_UPDATE = 'GUILD_ROLE_UPDATE', 26 | GUILD_ROLE_DELETE = 'GUILD_ROLE_DELETE', 27 | GUILD_SCHEDULED_EVENT_CREATE = 'GUILD_SCHEDULED_EVENT_CREATE', 28 | GUILD_SCHEDULED_EVENT_UPDATE = 'GUILD_SCHEDULED_EVENT_UPDATE', 29 | GUILD_SCHEDULED_EVENT_DELETE = 'GUILD_SCHEDULED_EVENT_DELETE', 30 | GUILD_SCHEDULED_EVENT_USER_ADD = 'GUILD_SCHEDULED_EVENT_USER_ADD', 31 | GUILD_SCHEDULED_EVENT_USER_REMOVE = 'GUILD_SCHEDULED_EVENT_USER_REMOVE', 32 | INTERACTION_CREATE = 'INTERACTION_CREATE', 33 | INVITE_CREATE = 'INVITE_CREATE', 34 | INVITE_DELETE = 'INVITE_DELETE', 35 | MESSAGE_CREATE = 'MESSAGE_CREATE', 36 | MESSAGE_UPDATE = 'MESSAGE_UPDATE', 37 | MESSAGE_DELETE = 'MESSAGE_DELETE', 38 | MESSAGE_DELETE_BULK = 'MESSAGE_DELETE_BULK', 39 | MESSAGE_REACTION_ADD = 'MESSAGE_REACTION_ADD', 40 | MESSAGE_REACTION_REMOVE = 'MESSAGE_REACTION_REMOVE', 41 | MESSAGE_REACTION_REMOVE_ALL = 'MESSAGE_REACTION_REMOVE_ALL', 42 | MESSAGE_REACTION_REMOVE_EMOJI = 'MESSAGE_REACTION_REMOVE_EMOJI', 43 | PRESENCE_UPDATE = 'PRESENCE_UPDATE', 44 | STAGE_INSTANCE_CREATE = 'STAGE_INSTANCE_CREATE', 45 | STAGE_INSTANCE_UPDATE = 'STAGE_INSTANCE_UPDATE', 46 | STAGE_INSTANCE_DELETE = 'STAGE_INSTANCE_DELETE', 47 | THREAD_CREATE = 'THREAD_CREATE', 48 | THREAD_UPDATE = 'THREAD_UPDATE', 49 | THREAD_DELETE = 'THREAD_DELETE', 50 | THREAD_LIST_SYNC = 'THREAD_LIST_SYNC', 51 | THREAD_MEMBER_UPDATE = 'THREAD_MEMBER_UPDATE', 52 | THREAD_MEMBERS_UPDATE = 'THREAD_MEMBERS_UPDATE', 53 | TYPING_START = 'TYPING_START', 54 | USER_UPDATE = 'USER_UPDATE', 55 | VOICE_STATE_UPDATE = 'VOICE_STATE_UPDATE', 56 | VOICE_SERVER_UPDATE = 'VOICE_SERVER_UPDATE', 57 | WEBHOOKS_UPDATE = 'WEBHOOKS_UPDATE', 58 | } 59 | 60 | export type EventTypes = { 61 | [Events.READY]: { 62 | v: number; 63 | user: types.User; 64 | guilds: types.UnavailableGuild[]; 65 | session_id: string; 66 | shard?: [shard_id: number, num_shards: number]; 67 | application: Required>; 71 | }; 72 | [Events.RESUMED]: {}; 73 | [Events.APPLICATION_COMMAND_PERMISSIONS_UPDATE]: types.ApplicationCommandPermissions; 74 | [Events.CHANNEL_CREATE]: types.GuildChannel; 75 | [Events.CHANNEL_UPDATE]: types.GuildChannel | types.GroupDMChannel; 76 | [Events.CHANNEL_DELETE]: types.GuildChannel | types.GroupDMChannel; 77 | [Events.CHANNEL_PINS_UPDATE]: { 78 | guild_id?: string; 79 | channel_id: string; 80 | last_pin_timestamp?: string | null; 81 | }; 82 | [Events.THREAD_CREATE]: types.Thread; 83 | [Events.THREAD_UPDATE]: types.Thread; 84 | [Events.THREAD_DELETE]: types.Thread; 85 | [Events.THREAD_LIST_SYNC]: { 86 | guild_id: string; 87 | channel_ids?: string[]; 88 | threads: types.Thread[]; 89 | members: types.ThreadMember[]; 90 | }; 91 | [Events.THREAD_MEMBER_UPDATE]: types.ThreadMember & { guild_id: string; }; 92 | [Events.THREAD_MEMBERS_UPDATE]: { 93 | id: string; 94 | guild_id: string; 95 | member_count: number; 96 | added_members?: (types.ThreadMember & types.Member & types.Presence)[]; 97 | removed_member_ids?: string[]; 98 | }; 99 | [Events.GUILD_CREATE]: types.Guild & { 100 | joined_at: string; 101 | large: boolean; 102 | unavailable: boolean; 103 | member_count: number; 104 | voice_states: types.VoiceState[]; 105 | members: types.Member[]; 106 | channels: types.GuildChannel[]; 107 | threads: types.Thread[]; 108 | presences: types.Presence[]; 109 | stage_instances: types.StageInstance[]; 110 | guild_scheduled_events: types.ScheduledEvent[]; 111 | }; 112 | [Events.GUILD_UPDATE]: types.Guild; 113 | [Events.GUILD_DELETE]: types.UnavailableGuild; 114 | [Events.GUILD_BAN_ADD]: { 115 | guild_id: string; 116 | user: types.User; 117 | }; 118 | [Events.GUILD_BAN_REMOVE]: { 119 | guild_id: string; 120 | user: types.User; 121 | }; 122 | [Events.GUILD_EMOJIS_UPDATE]: { 123 | guild_id: string; 124 | user: types.Emoji[]; 125 | }; 126 | [Events.GUILD_INTEGRATIONS_UPDATE]: { guild_id: string; }; 127 | [Events.GUILD_MEMBER_ADD]: types.Member & { guild_id: string; }; 128 | [Events.GUILD_MEMBER_REMOVE]: { 129 | guild_id: string; 130 | user: types.User; 131 | }; 132 | [Events.GUILD_MEMBER_UPDATE]: { 133 | guild_id: string; 134 | roles: string[]; 135 | user: types.User; 136 | nick?: string | null; 137 | avatar: string | null; 138 | joined_at: string | null; 139 | premium_since?: string | null; 140 | deaf?: boolean; 141 | mute?: boolean; 142 | pending?: boolean; 143 | communication_disabled_until?: string | null; 144 | }; 145 | [Events.GUILD_MEMBERS_CHUNK]: { 146 | guild_id: string; 147 | members: types.Member[]; 148 | chunk_index: number; 149 | chunk_count: number; 150 | not_found?: []; 151 | presences?: types.Presence[]; 152 | nonce?: string; 153 | }; 154 | [Events.GUILD_ROLE_CREATE]: { 155 | guild_id: string; 156 | role: types.Role; 157 | }; 158 | [Events.GUILD_ROLE_UPDATE]: { 159 | guild_id: string; 160 | role: types.Role; 161 | }; 162 | [Events.GUILD_ROLE_DELETE]: { 163 | guild_id: string; 164 | role_id: string; 165 | }; 166 | [Events.INTERACTION_CREATE]: types.Interaction; 167 | [Events.INVITE_CREATE]: { 168 | channel_id: string; 169 | code: string; 170 | created_at: string; 171 | guild_id?: string; 172 | inviter?: types.User; 173 | max_age: number; 174 | max_uses: number; 175 | target_type?: InviteTargetTypes; 176 | target_user?: types.User; 177 | target_application?: types.Application; 178 | temporary: boolean; 179 | uses: number; 180 | }; 181 | [Events.INVITE_DELETE]: { 182 | channel_id: string; 183 | guild_id?: string; 184 | code: string; 185 | }; 186 | [Events.MESSAGE_CREATE]: types.Message; 187 | [Events.MESSAGE_UPDATE]: types.Message; 188 | [Events.MESSAGE_DELETE]: { 189 | id: string; 190 | channel_id: string; 191 | guild_id?: string; 192 | }; 193 | [Events.MESSAGE_DELETE_BULK]: { 194 | ids: string[]; 195 | channel_id: string; 196 | guild_id?: string; 197 | }; 198 | [Events.MESSAGE_REACTION_ADD]: { 199 | user_id: string; 200 | channel_id: string; 201 | message_id: string; 202 | guild_id?: string; 203 | member?: types.Member; 204 | emoji: types.Emoji; 205 | }; 206 | [Events.MESSAGE_REACTION_REMOVE]: { 207 | user_id: string; 208 | channel_id: string; 209 | message_id: string; 210 | guild_id?: string; 211 | emoji: types.Emoji; 212 | }; 213 | [Events.MESSAGE_REACTION_REMOVE_ALL]: { 214 | channel_id: string; 215 | message_id: string; 216 | guild_id?: string; 217 | }; 218 | [Events.MESSAGE_REACTION_REMOVE_EMOJI]: { 219 | channel_id: string; 220 | guild_id?: string; 221 | message_id: string; 222 | emoji: types.Emoji; 223 | }; 224 | [Events.PRESENCE_UPDATE]: types.Presence; 225 | [Events.TYPING_START]: { 226 | channel_id: string; 227 | guild_id?: string; 228 | user_id: string; 229 | timestamp: number; 230 | member?: types.Member; 231 | }; 232 | [Events.USER_UPDATE]: types.User; 233 | [Events.VOICE_STATE_UPDATE]: types.VoiceState; 234 | [Events.VOICE_SERVER_UPDATE]: { 235 | token: string; 236 | guild_id: string; 237 | endpoint: string; 238 | }; 239 | [Events.WEBHOOKS_UPDATE]: { 240 | guild_id: string; 241 | channel_id: string; 242 | }; 243 | [Events.STAGE_INSTANCE_CREATE]: types.StageInstance; 244 | [Events.STAGE_INSTANCE_UPDATE]: types.StageInstance; 245 | [Events.STAGE_INSTANCE_DELETE]: types.StageInstance; 246 | [Events.GUILD_SCHEDULED_EVENT_CREATE]: types.ScheduledEvent; 247 | [Events.GUILD_SCHEDULED_EVENT_UPDATE]: types.ScheduledEvent; 248 | [Events.GUILD_SCHEDULED_EVENT_DELETE]: types.ScheduledEvent; 249 | [Events.GUILD_SCHEDULED_EVENT_USER_ADD]: { 250 | guild_scheduled_event_id: string; 251 | user_id: string; 252 | guild_id: string; 253 | }; 254 | [Events.GUILD_SCHEDULED_EVENT_USER_REMOVE]: { 255 | guild_scheduled_event_id: string; 256 | user_id: string; 257 | guild_id: string; 258 | }; 259 | }; 260 | 261 | export interface EventHandler extends EventEmitter { 262 | on(event: E, callback: (data: EventTypes[E]) => void): this; 263 | once(event: E, callback: (data: EventTypes[E]) => void): this; 264 | off(event: E, callback: (data: EventTypes[E]) => void): this; 265 | } 266 | -------------------------------------------------------------------------------- /src/client.ts: -------------------------------------------------------------------------------- 1 | import { WebSocket, RawData } from 'ws'; 2 | import { EventEmitter } from 'events'; 3 | import { Intents, TokenTypes, API_VERSION, ActivityTypes, StatusTypes } from './helpers'; 4 | import { SafeJsonParse, TimestampString } from './_common'; 5 | import { Authorization } from './authorization'; 6 | import { Gateway } from './actions'; 7 | import { Events, EventTypes, EventHandler } from './events'; 8 | import type { SessionStartLimit } from './types'; 9 | 10 | const enum OPCodes { 11 | DISPATCH = 0, 12 | HEARTBEAT = 1, 13 | IDENTIFY = 2, 14 | PRESENCE_UPDATE = 3, 15 | VOICE_STATE_UPDATE = 4, 16 | RESUME = 6, 17 | RECONNECT = 7, 18 | REQUEST_GUILD_MEMBERS = 8, 19 | INVALID_SESSION = 9, 20 | HELLO = 10, 21 | HEARTBEAT_ACK = 11, 22 | } 23 | 24 | type Session = { 25 | id: string; 26 | seq: number; 27 | }; 28 | 29 | type DispatchPacket = { 30 | t: E; 31 | s?: number; 32 | d: EventTypes[E]; 33 | }; 34 | 35 | type PacketTypes = { 36 | [OPCodes.DISPATCH]: DispatchPacket; 37 | [OPCodes.HELLO]: { 38 | d: { heartbeat_interval: number; }; 39 | }; 40 | [OPCodes.HEARTBEAT_ACK]: {}; 41 | [OPCodes.HEARTBEAT]: {}; 42 | [OPCodes.INVALID_SESSION]: { 43 | d: boolean; 44 | }; 45 | [OPCodes.RECONNECT]: {}; 46 | }; 47 | 48 | type Packet = { op: T; } & PacketTypes[T]; 49 | 50 | type PacketHandlers = { 51 | [T in keyof PacketTypes]?: (data: Packet) => void; 52 | }; 53 | 54 | type DispatchHandlers = { 55 | [E in Events]?: (data: EventTypes[E]) => void; 56 | }; 57 | 58 | const 59 | FATAL_CODES = Object.freeze([4004, 4010, 4011, 4012, 4013, 4014]), 60 | DROP_CODES = Object.freeze([4007, 4009]), 61 | RECONNECT_TIMEOUT = 5000; 62 | 63 | const AfterMessage = (after: number) => 64 | `Reset after: ${TimestampString(Date.now() + after)}`; 65 | 66 | export class Client extends EventEmitter { 67 | private _ws?: WebSocket; 68 | private _authorization?: Authorization; 69 | private _intents?: Intents; 70 | private _shard?: [number, number]; 71 | private _eventHandler: EventHandler = new EventEmitter(); 72 | private _heartbeatTimer?: NodeJS.Timer; 73 | private _lastHeartbeatAck = false; 74 | private _session?: Session; 75 | 76 | private _props?: object | null = { 77 | $os: 'linux', 78 | $browser: 'bot', 79 | $device: 'bot', 80 | }; 81 | 82 | constructor() { 83 | super(); 84 | } 85 | 86 | private _wsConnect = async (resume?: boolean) => { 87 | this._wsDisconnect(); 88 | 89 | if(!resume) 90 | this._session = undefined; 91 | 92 | const { _authorization: authorization } = this; 93 | 94 | const response: { 95 | url: string; 96 | session_start_limit?: SessionStartLimit; 97 | } | undefined = await ( 98 | (authorization?.type == TokenTypes.BOT) ? 99 | Gateway.GetBot : Gateway.Get 100 | )({ authorization }).catch(() => undefined); 101 | 102 | if(this._ws) 103 | return this.emit(ClientEvents.WARN, 'The client is already connected.'); 104 | 105 | if(!response) 106 | return this.emit(ClientEvents.FATAL, 'Unable to connect to the gateway API.'); 107 | 108 | const { url, session_start_limit } = response; 109 | 110 | if(typeof url != 'string') 111 | return this.emit(ClientEvents.FATAL, 'Unexpected gateway API response.'); 112 | 113 | if(!this._session && session_start_limit) { 114 | const { remaining, total, reset_after } = session_start_limit; 115 | 116 | if(remaining < 1) 117 | return this.emit(ClientEvents.FATAL, `Max session start limit reached. ${AfterMessage(reset_after)}`); 118 | 119 | this.emit(ClientEvents.INFO, `Session starts avaliable: ${remaining}/${total}. ${AfterMessage(reset_after)}`); 120 | } 121 | 122 | try { 123 | this._ws = new WebSocket(`${url}?v=${API_VERSION}`); 124 | } catch { 125 | return this.emit(ClientEvents.FATAL, 'Unable to create a socket.'); 126 | } 127 | 128 | this._ws.on('message', this._onMessage); 129 | this._ws.on('close', this._onClose); 130 | this._ws.on('error', this._onError); 131 | }; 132 | 133 | private _wsDisconnect = (code = 1012) => { 134 | const ws = this._ws; 135 | if(!ws) return; 136 | this._setHeartbeatTimer(); 137 | this.emit(ClientEvents.DISCONNECT, code); 138 | this._ws = undefined; 139 | ws.removeAllListeners(); 140 | ws.close(code); 141 | }; 142 | 143 | private _send = (op: OPCodes, d: any) => 144 | this._ws?.send(JSON.stringify({ op, d })); 145 | 146 | private _dispatchHandlers: DispatchHandlers = { 147 | [Events.READY]: ({ session_id }) => { 148 | this._session = { 149 | id: session_id, 150 | seq: 0, 151 | }; 152 | this.emit(ClientEvents.CONNECT); 153 | }, 154 | 155 | [Events.RESUMED]: () => 156 | this.emit(ClientEvents.CONNECT), 157 | }; 158 | 159 | private _packetHandlers: PacketHandlers = { 160 | [OPCodes.DISPATCH]: (packet: DispatchPacket) => { 161 | const 162 | { t, s, d } = packet, 163 | session = this._session; 164 | 165 | if(s && session && (s > session.seq)) 166 | session.seq = s; 167 | 168 | this._dispatchHandlers[t]?.(d); 169 | this.emit(ClientEvents.INTENT, packet); 170 | this._eventHandler.emit(t, d); 171 | }, 172 | 173 | [OPCodes.HELLO]: ({ d: { heartbeat_interval } }) => { 174 | this._identify(); 175 | this._lastHeartbeatAck = true; 176 | this._setHeartbeatTimer(heartbeat_interval); 177 | this._sendHeartbeat(); 178 | }, 179 | 180 | [OPCodes.HEARTBEAT_ACK]: () => 181 | this._lastHeartbeatAck = true, 182 | 183 | [OPCodes.HEARTBEAT]: () => 184 | this._sendHeartbeat(), 185 | 186 | [OPCodes.INVALID_SESSION]: ({ d }) => { 187 | this.emit(ClientEvents.WARN, `Invalid session. Resumable: ${d}`); 188 | this._wsConnect(d); 189 | }, 190 | 191 | [OPCodes.RECONNECT]: () => { 192 | this.emit(ClientEvents.WARN, 'Server forced reconnect.'); 193 | this._wsConnect(true); 194 | }, 195 | }; 196 | 197 | private _onMessage = (data: RawData) => { 198 | const packet = SafeJsonParse>(String(data)); 199 | if(!packet) return; 200 | this._packetHandlers[packet.op]?.(packet); 201 | }; 202 | 203 | private _identify = () => this._session ? 204 | this._send(OPCodes.RESUME, { 205 | token: this._authorization?.token, 206 | session_id: this._session.id, 207 | seq: this._session.seq, 208 | }) : 209 | this._send(OPCodes.IDENTIFY, { 210 | token: this._authorization?.token, 211 | properties: this._props, 212 | intents: this._intents ?? Intents.SYSTEM, 213 | shard: this._shard, 214 | }); 215 | 216 | private _sendHeartbeat = () => { 217 | if(this._ws?.readyState != 1) return; 218 | if(!this._lastHeartbeatAck) { 219 | this.emit(ClientEvents.WARN, 'Heartbeat timeout.'); 220 | this._wsConnect(true); 221 | return; 222 | } 223 | this._lastHeartbeatAck = false; 224 | this._send(OPCodes.HEARTBEAT, this._session?.seq ?? 0); 225 | }; 226 | 227 | private _setHeartbeatTimer = (interval?: number) => { 228 | this._heartbeatTimer && clearInterval(this._heartbeatTimer); 229 | this._heartbeatTimer = interval ? 230 | setInterval(this._sendHeartbeat, interval) : undefined; 231 | }; 232 | 233 | private _onClose = (code: number) => { 234 | this._wsDisconnect(code); 235 | FATAL_CODES.includes(code) ? 236 | this.emit(ClientEvents.FATAL, `Fatal error. Code: ${code}`) : 237 | setTimeout(this._wsConnect, RECONNECT_TIMEOUT, !DROP_CODES.includes(code)); 238 | }; 239 | 240 | private _onError = (error: Error) => 241 | this.emit(ClientEvents.ERROR, error); 242 | 243 | Connect = ( 244 | authorization: Authorization, 245 | intents?: Intents, 246 | shard?: { 247 | id: number; 248 | total: number; 249 | }, 250 | ) => { 251 | this._authorization = authorization; 252 | this._intents = intents; 253 | this._shard = shard ? 254 | [shard.id, shard.total] : undefined; 255 | this._wsConnect(); 256 | }; 257 | 258 | Resume = ( 259 | authorization: Authorization, 260 | session: Session, 261 | ) => { 262 | this._authorization = authorization; 263 | this._session = session; 264 | this._wsConnect(true); 265 | }; 266 | 267 | Disconnect = (code?: number) => 268 | this._wsDisconnect(code); 269 | 270 | RequestGuildMembers = (params: { 271 | guild_id: string; 272 | presences?: boolean; 273 | nonce?: string; 274 | } & ({ 275 | query: string; 276 | limit: number; 277 | } | { 278 | user_ids: string | string[]; 279 | })) => { 280 | if(!this._ws) throw 'No connection.'; 281 | this._send(OPCodes.REQUEST_GUILD_MEMBERS, params); 282 | }; 283 | 284 | UpdateVoiceState = (params: { 285 | guild_id: string; 286 | channel_id: string | null; 287 | self_mute: boolean; 288 | self_deaf: boolean; 289 | }) => { 290 | if(!this._ws) throw 'No connection.'; 291 | this._send(OPCodes.VOICE_STATE_UPDATE, params); 292 | }; 293 | 294 | UpdatePresence = (params: { 295 | since: number | null; 296 | activities: { 297 | name: string; 298 | type: ActivityTypes; 299 | url?: string; 300 | }[]; 301 | status: StatusTypes; 302 | afk: boolean; 303 | }) => { 304 | if(!this._ws) throw 'No connection.'; 305 | this._send(OPCodes.PRESENCE_UPDATE, params); 306 | }; 307 | 308 | get events() { return this._eventHandler; } 309 | get props() { return this._props; } 310 | set props(value) { this._props = value; } 311 | 312 | get session() { 313 | if(!this._session) return; 314 | return Object.assign({}, this._session); 315 | } 316 | } 317 | 318 | export enum ClientEvents { 319 | CONNECT = 'connect', 320 | DISCONNECT = 'disconnect', 321 | INTENT = 'intent', 322 | INFO = 'info', 323 | WARN = 'warn', 324 | ERROR = 'error', 325 | FATAL = 'fatal', 326 | } 327 | 328 | type DispatchPackets = { 329 | [E in Events]: DispatchPacket; 330 | }; 331 | 332 | type ClientEventTypes = { 333 | [ClientEvents.CONNECT]: void; 334 | [ClientEvents.DISCONNECT]: number; 335 | [ClientEvents.INTENT]: DispatchPackets[keyof DispatchPackets]; 336 | [ClientEvents.INFO]: string; 337 | [ClientEvents.WARN]: string; 338 | [ClientEvents.ERROR]: Error; 339 | [ClientEvents.FATAL]: string; 340 | }; 341 | 342 | export interface Client extends EventEmitter { 343 | on(event: E, callback: (data: ClientEventTypes[E]) => void): this; 344 | once(event: E, callback: (data: ClientEventTypes[E]) => void): this; 345 | off(event: E, callback: (data: ClientEventTypes[E]) => void): this; 346 | } 347 | -------------------------------------------------------------------------------- /src/helpers.ts: -------------------------------------------------------------------------------- 1 | export const 2 | HOST = 'https://discord.com', 3 | API = `${HOST}/api` as const, 4 | API_VERSION = 10, 5 | API_PATH = `${API}/v${API_VERSION}` as const, 6 | CDN = 'https://cdn.discordapp.com'; 7 | 8 | export enum TokenTypes { 9 | BOT = 'Bot', 10 | BEARER = 'Bearer', 11 | NONE = '', 12 | } 13 | 14 | export const Permissions = { 15 | NO_PERMISSIONS: 0n, 16 | CREATE_INSTANT_INVITE: 1n, 17 | KICK_MEMBERS: 1n << 1n, 18 | BAN_MEMBERS: 1n << 2n, 19 | ADMINISTRATOR: 1n << 3n, 20 | MANAGE_CHANNELS: 1n << 4n, 21 | MANAGE_GUILD: 1n << 5n, 22 | ADD_REACTIONS: 1n << 6n, 23 | VIEW_AUDIT_LOG: 1n << 7n, 24 | PRIORITY_SPEAKER: 1n << 8n, 25 | STREAM: 1n << 9n, 26 | VIEW_CHANNEL: 1n << 10n, 27 | SEND_MESSAGES: 1n << 11n, 28 | SEND_TTS_MESSAGES: 1n << 12n, 29 | MANAGE_MESSAGES: 1n << 13n, 30 | EMBED_LINKS: 1n << 14n, 31 | ATTACH_FILES: 1n << 15n, 32 | READ_MESSAGE_HISTORY: 1n << 16n, 33 | MENTION_EVERYONE: 1n << 17n, 34 | USE_EXTERNAL_EMOJIS: 1n << 18n, 35 | VIEW_GUILD_INSIGHTS: 1n << 19n, 36 | CONNECT: 1n << 20n, 37 | SPEAK: 1n << 21n, 38 | MUTE_MEMBERS: 1n << 22n, 39 | DEAFEN_MEMBERS: 1n << 23n, 40 | MOVE_MEMBERS: 1n << 24n, 41 | USE_VAD: 1n << 25n, 42 | CHANGE_NICKNAME: 1n << 26n, 43 | MANAGE_NICKNAMES: 1n << 27n, 44 | MANAGE_ROLES: 1n << 28n, 45 | MANAGE_WEBHOOKS: 1n << 29n, 46 | MANAGE_EMOJIS_AND_STICKERS: 1n << 30n, 47 | USE_APPLICATION_COMMANDS: 1n << 31n, 48 | REQUEST_TO_SPEAK: 1n << 32n, 49 | MANAGE_EVENTS: 1n << 33n, 50 | MANAGE_THREADS: 1n << 34n, 51 | CREATE_PUBLIC_THREADS: 1n << 35n, 52 | CREATE_PRIVATE_THREADS: 1n << 36n, 53 | USE_EXTERNAL_STICKERS: 1n << 37n, 54 | SEND_MESSAGES_IN_THREADS: 1n << 38n, 55 | USE_EMBEDDED_ACTIVITIES: 1n << 39n, 56 | MODERATE_MEMBERS: 1n << 40n, 57 | } as const; 58 | 59 | export type Permission = typeof Permissions[keyof typeof Permissions]; 60 | 61 | export enum Intents { 62 | SYSTEM = 0, 63 | GUILDS = 1 << 0, 64 | GUILD_MEMBERS = 1 << 1, 65 | GUILD_BANS = 1 << 2, 66 | GUILD_EMOJIS = 1 << 3, 67 | GUILD_INTEGRATIONS = 1 << 4, 68 | GUILD_WEBHOOKS = 1 << 5, 69 | GUILD_INVITES = 1 << 6, 70 | GUILD_VOICE_STATES = 1 << 7, 71 | GUILD_PRESENCES = 1 << 8, 72 | GUILD_MESSAGES = 1 << 9, 73 | GUILD_MESSAGE_REACTIONS = 1 << 10, 74 | GUILD_MESSAGE_TYPING = 1 << 11, 75 | DIRECT_MESSAGES = 1 << 12, 76 | DIRECT_MESSAGE_REACTIONS = 1 << 13, 77 | DIRECT_MESSAGE_TYPING = 1 << 14, 78 | MESSAGE_CONTENT = 1 << 15, 79 | GUILD_SCHEDULED_EVENTS = 1 << 16, 80 | } 81 | 82 | export enum AuditLogEvents { 83 | GUILD_UPDATE = 1, 84 | CHANNEL_CREATE = 10, 85 | CHANNEL_UPDATE = 11, 86 | CHANNEL_DELETE = 12, 87 | CHANNEL_OVERWRITE_CREATE = 13, 88 | CHANNEL_OVERWRITE_UPDATE = 14, 89 | CHANNEL_OVERWRITE_DELETE = 15, 90 | MEMBER_KICK = 20, 91 | MEMBER_PRUNE = 21, 92 | MEMBER_BAN_ADD = 22, 93 | MEMBER_BAN_REMOVE = 23, 94 | MEMBER_UPDATE = 24, 95 | MEMBER_ROLE_UPDATE = 25, 96 | MEMBER_MOVE = 26, 97 | MEMBER_DISCONNECT = 27, 98 | BOT_ADD = 28, 99 | ROLE_CREATE = 30, 100 | ROLE_UPDATE = 31, 101 | ROLE_DELETE = 32, 102 | INVITE_CREATE = 40, 103 | INVITE_UPDATE = 41, 104 | INVITE_DELETE = 42, 105 | WEBHOOK_CREATE = 50, 106 | WEBHOOK_UPDATE = 51, 107 | WEBHOOK_DELETE = 52, 108 | EMOJI_CREATE = 60, 109 | EMOJI_UPDATE = 61, 110 | EMOJI_DELETE = 62, 111 | MESSAGE_DELETE = 72, 112 | MESSAGE_BULK_DELETE = 73, 113 | MESSAGE_PIN = 74, 114 | MESSAGE_UNPIN = 75, 115 | INTEGRATION_CREATE = 80, 116 | INTEGRATION_UPDATE = 81, 117 | INTEGRATION_DELETE = 82, 118 | STAGE_INSTANCE_CREATE = 83, 119 | STAGE_INSTANCE_UPDATE = 84, 120 | STAGE_INSTANCE_DELETE = 85, 121 | STICKER_CREATE = 90, 122 | STICKER_UPDATE = 91, 123 | STICKER_DELETE = 92, 124 | GUILD_SCHEDULED_EVENT_CREATE = 100, 125 | GUILD_SCHEDULED_EVENT_UPDATE = 101, 126 | GUILD_SCHEDULED_EVENT_DELETE = 102, 127 | THREAD_CREATE = 110, 128 | THREAD_UPDATE = 111, 129 | THREAD_DELETE = 112, 130 | APPLICATION_COMMAND_PERMISSION_UPDATE = 121, 131 | } 132 | 133 | export enum ChannelTypes { 134 | GUILD_TEXT = 0, 135 | DM = 1, 136 | GUILD_VOICE = 2, 137 | GROUP_DM = 3, 138 | GUILD_CATEGORY = 4, 139 | GUILD_NEWS = 5, 140 | GUILD_NEWS_THREAD = 10, 141 | GUILD_PUBLIC_THREAD = 11, 142 | GUILD_PRIVATE_THREAD = 12, 143 | GUILD_STAGE_VOICE = 13, 144 | GUILD_DIRECTORY = 14, 145 | GUILD_FORUM = 15, 146 | } 147 | 148 | export enum MessageTypes { 149 | DEFAULT = 0, 150 | RECIPIENT_ADD = 1, 151 | RECIPIENT_REMOVE = 2, 152 | CALL = 3, 153 | CHANNEL_NAME_CHANGE = 4, 154 | CHANNEL_ICON_CHANGE = 5, 155 | CHANNEL_PINNED_MESSAGE = 6, 156 | GUILD_MEMBER_JOIN = 7, 157 | USER_PREMIUM_GUILD_SUBSCRIPTION = 8, 158 | USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1 = 9, 159 | USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2 = 10, 160 | USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3 = 11, 161 | CHANNEL_FOLLOW_ADD = 12, 162 | GUILD_DISCOVERY_DISQUALIFIED = 14, 163 | GUILD_DISCOVERY_REQUALIFIED = 15, 164 | GUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING = 16, 165 | GUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING = 17, 166 | THREAD_CREATED = 18, 167 | REPLY = 19, 168 | CHAT_INPUT_COMMAND = 20, 169 | THREAD_STARTER_MESSAGE = 21, 170 | GUILD_INVITE_REMINDER = 22, 171 | CONTEXT_MENU_COMMAND = 23, 172 | } 173 | 174 | export enum MessageActivityTypes { 175 | JOIN = 1, 176 | SPECTATE = 2, 177 | LISTEN = 3, 178 | JOIN_REQUEST = 5, 179 | } 180 | 181 | export enum MessageFlags { 182 | NO_FLAGS = 0, 183 | CROSSPOSTED = 1 << 0, 184 | IS_CROSSPOST = 1 << 1, 185 | SUPPRESS_EMBEDS = 1 << 2, 186 | SOURCE_MESSAGE_DELETED = 1 << 3, 187 | URGENT = 1 << 4, 188 | HAS_THREAD = 1 << 5, 189 | EPHEMERAL = 1 << 6, 190 | LOADING = 1 << 7, 191 | FAILED_TO_MENTION_SOME_ROLES_IN_THREAD = 1 << 8, 192 | } 193 | 194 | export enum MessageStickerFormatTypes { 195 | PNG = 1, 196 | APNG = 2, 197 | LOTTIE = 3, 198 | } 199 | 200 | export enum PermissionsOverwriteTypes { 201 | ROLE = 0, 202 | MEMBER = 1, 203 | } 204 | 205 | export enum AllowedMentionTypes { 206 | ROLES = 'roles', 207 | USERS = 'users', 208 | EVERYONE = 'everyone', 209 | } 210 | 211 | export enum DefaultMessageNotificationLevels { 212 | ALL_MESSAGES = 0, 213 | ONLY_MENTIONS = 1, 214 | } 215 | 216 | export enum ExplicitContentFilterLevels { 217 | DISABLED = 0, 218 | MEMBERS_WITHOUT_ROLES = 1, 219 | ALL_MEMBERS = 2, 220 | } 221 | 222 | export enum MFA_Levels { 223 | NONE = 0, 224 | ELEVATED = 1, 225 | } 226 | 227 | export enum VerificationLevels { 228 | NONE = 0, 229 | LOW = 1, 230 | MEDIUM = 2, 231 | HIGH = 3, 232 | VERY_HIGH = 4, 233 | } 234 | 235 | export enum SystemChannelFlags { 236 | NO_FLAGS = 0, 237 | SUPPRESS_JOIN_NOTIFICATIONS = 1 << 0, 238 | SUPPRESS_PREMIUM_SUBSCRIPTIONS = 1 << 1, 239 | SUPPRESS_GUILD_REMINDER_NOTIFICATIONS = 1 << 2, 240 | SUPPRESS_JOIN_NOTIFICATION_REPLIES = 1 << 3, 241 | } 242 | 243 | export enum GuildFeatures { 244 | ANIMATED_BANNER = 'ANIMATED_BANNER', 245 | ANIMATED_ICON = 'ANIMATED_ICON', 246 | BANNER = 'BANNER', 247 | COMMERCE = 'COMMERCE', 248 | COMMUNITY = 'COMMUNITY', 249 | DISCOVERABLE = 'DISCOVERABLE', 250 | FEATURABLE = 'FEATURABLE', 251 | INVITE_SPLASH = 'INVITE_SPLASH', 252 | MEMBER_VERIFICATION_GATE_ENABLED = 'MEMBER_VERIFICATION_GATE_ENABLED', 253 | MONETIZATION_ENABLED = 'MONETIZATION_ENABLED', 254 | MORE_STICKERS = 'MORE_STICKERS', 255 | NEWS = 'NEWS', 256 | PARTNERED = 'PARTNERED', 257 | PREVIEW_ENABLED = 'PREVIEW_ENABLED', 258 | PRIVATE_THREADS = 'PRIVATE_THREADS', 259 | ROLE_ICONS = 'ROLE_ICONS', 260 | TICKETED_EVENTS_ENABLED = 'TICKETED_EVENTS_ENABLED', 261 | VANITY_URL = 'VANITY_URL', 262 | VERIFIED = 'VERIFIED', 263 | VIP_REGIONS = 'VIP_REGIONS', 264 | WELCOME_SCREEN_ENABLED = 'WELCOME_SCREEN_ENABLED', 265 | } 266 | 267 | export enum IntegrationExpireBehaviors { 268 | REMOVE_ROLE = 0, 269 | KICK = 1, 270 | } 271 | 272 | export enum PremiumTiers { 273 | NONE = 0, 274 | TIER_1 = 1, 275 | TIER_2 = 2, 276 | TIER_3 = 3, 277 | } 278 | 279 | export enum ActivityTypes { 280 | PLAYING = 0, 281 | STREAMING = 1, 282 | LISTENING = 2, 283 | WATCHING = 3, 284 | CUSTOM_STATUS = 4, 285 | COMPETING = 5, 286 | } 287 | 288 | export enum StatusTypes { 289 | ONLINE = 'online', 290 | DO_NOT_DISTURB = 'dnd', 291 | IDLE = 'idle', 292 | INVISIBLE = 'invisible', 293 | OFFLINE = 'offline', 294 | } 295 | 296 | export enum WidgetStyleOptions { 297 | SHIELD = 'shield', 298 | BANNER1 = 'banner1', 299 | BANNER2 = 'banner2', 300 | BANNER3 = 'banner3', 301 | BANNER4 = 'banner4', 302 | } 303 | 304 | export enum UserFlags { 305 | NO_FLAGS = 0, 306 | STAFF = 1 << 0, 307 | PARTNER = 1 << 1, 308 | HYPESQUAD = 1 << 2, 309 | BUG_HUNTER_LEVEL_1 = 1 << 3, 310 | HYPESQUAD_ONLINE_HOUSE_1 = 1 << 6, 311 | HYPESQUAD_ONLINE_HOUSE_2 = 1 << 7, 312 | HYPESQUAD_ONLINE_HOUSE_3 = 1 << 8, 313 | PREMIUM_EARLY_SUPPORTER = 1 << 9, 314 | TEAM_PSEUDO_USER = 1 << 10, 315 | BUG_HUNTER_LEVEL_2 = 1 << 14, 316 | VERIFIED_BOT = 1 << 16, 317 | VERIFIED_DEVELOPER = 1 << 17, 318 | CERTIFIED_MODERATOR = 1 << 18, 319 | BOT_HTTP_INTERACTIONS = 1 << 19, 320 | } 321 | 322 | export enum PremiumTypes { 323 | NONE = 0, 324 | NITRO_CLASSIC = 1, 325 | NITRO = 2, 326 | } 327 | 328 | export enum VisibilityTypes { 329 | NONE = 0, 330 | EVERYONE = 1, 331 | } 332 | 333 | export enum WebhookTypes { 334 | INCOMING = 1, 335 | CHANNEL_FOLLOWER = 2, 336 | APPLICATION = 3, 337 | } 338 | 339 | export enum ActivityFlags { 340 | NO_FLAGS = 0, 341 | INSTANCE = 1 << 0, 342 | JOIN = 1 << 1, 343 | SPECTATE = 1 << 2, 344 | JOIN_REQUEST = 1 << 3, 345 | SYNC = 1 << 4, 346 | PLAY = 1 << 5, 347 | PARTY_PRIVACY_FRIENDS = 1 << 6, 348 | PARTY_PRIVACY_VOICE_CHANNEL = 1 << 7, 349 | EMBEDDED = 1 << 8, 350 | } 351 | 352 | export enum ApplicationCommandOptionTypes { 353 | SUB_COMMAND = 1, 354 | SUB_COMMAND_GROUP = 2, 355 | STRING = 3, 356 | INTEGER = 4, 357 | BOOLEAN = 5, 358 | USER = 6, 359 | CHANNEL = 7, 360 | ROLE = 8, 361 | MENTIONABLE = 9, 362 | NUMBER = 10, 363 | ATTACHMENT = 11, 364 | } 365 | 366 | export enum ApplicationCommandPermissionTypes { 367 | ROLE = 1, 368 | USER = 2, 369 | CHANNEL = 3, 370 | } 371 | 372 | export enum InteractionTypes { 373 | PING = 1, 374 | APPLICATION_COMMAND = 2, 375 | MESSAGE_COMPONENT = 3, 376 | APPLICATION_COMMAND_AUTOCOMPLETE = 4, 377 | MODAL_SUBMIT = 5, 378 | } 379 | 380 | export enum InteractionCallbackTypes { 381 | PONG = 1, 382 | CHANNEL_MESSAGE_WITH_SOURCE = 4, 383 | DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE = 5, 384 | DEFERRED_UPDATE_MESSAGE = 6, 385 | UPDATE_MESSAGE = 7, 386 | APPLICATION_COMMAND_AUTOCOMPLETE_RESULT = 8, 387 | MODAL = 9, 388 | } 389 | 390 | export enum OAuth2Scopes { 391 | ACTIVITIES_READ = 'activities.read', 392 | ACTIVITIES_WRITE = 'activities.write', 393 | APPLICATIONS_BUILDS_READ = 'applications.builds.read', 394 | APPLICATIONS_BUILDS_UPLOAD = 'applications.builds.upload', 395 | APPLICATIONS_COMMANDS = 'applications.commands', 396 | APPLICATIONS_COMMANDS_UPDATE = 'applications.commands.update', 397 | APPLICATIONS_COMMANDS_PERMISSIONS_UPDATE = 'applications.commands.permissions.update', 398 | APPLICATIONS_STORE_UPDATE = 'applications.store.update', 399 | APPLICATIONS_ENTITLEMENTS = 'applications.entitlements', 400 | BOT = 'bot', 401 | CONNECTIONS = 'connections', 402 | DM_CHANNELS_READ = 'dm_channels.read', 403 | EMAIL = 'email', 404 | GDM_JOIN = 'gdm.join', 405 | GUILDS = 'guilds', 406 | GUILDS_JOIN = 'guilds.join', 407 | GUILDS_MEMBERS_READ = 'guilds.members.read', 408 | IDENTIFY = 'identify', 409 | MESSAGES_READ = 'messages.read', 410 | RELATIONSHIPS_READ = 'relationships.read', 411 | RPC = 'rpc', 412 | RPC_ACTIVITIES_WRITE = 'rpc.activities.write', 413 | RPC_NOTIFICATIONS_READ = 'rpc.notifications.read', 414 | RPC_VOICE_READ = 'rpc.voice.read', 415 | RPC_VOICE_WRITE = 'rpc.voice.write', 416 | VOICE = 'voice', 417 | WEBHOOK_INCOMING = 'webhook.incoming', 418 | } 419 | 420 | export enum OAuth2GrantTypes { 421 | AUTHORIZATION_CODE = 'authorization_code', 422 | REFRESH_TOKEN = 'refresh_token', 423 | } 424 | 425 | export enum MembershipStates { 426 | INVITED = 1, 427 | ACCEPTED = 2, 428 | } 429 | 430 | export enum VoiceEncryptionModes { 431 | XSALSA20_POLY1305 = 'xsalsa20_poly1305', 432 | XSALSA20_POLY1305_SUFFIX = 'xsalsa20_poly1305_suffix', 433 | XSALSA20_POLY1305_LITE = 'xsalsa20_poly1305_lite', 434 | } 435 | 436 | export enum SpeakingStates { 437 | NO_FLAGS = 0, 438 | MICROPHONE = 1 << 0, 439 | SOUNDSHARE = 1 << 1, 440 | PRIORITY = 1 << 2, 441 | } 442 | 443 | export enum VideoQualityModes { 444 | AUTO = 1, 445 | FULL = 2, 446 | } 447 | 448 | export enum ComponentTypes { 449 | ACTION_ROW = 1, 450 | BUTTON = 2, 451 | SELECT_MENU = 3, 452 | TEXT_INPUT = 4, 453 | } 454 | 455 | export enum ButtonStyles { 456 | PRIMARY = 1, 457 | SECONDARY = 2, 458 | SUCCESS = 3, 459 | DANGER = 4, 460 | LINK = 5, 461 | } 462 | 463 | export enum PrivacyLevels { 464 | GUILD_ONLY = 2, 465 | } 466 | 467 | export enum GuildNSFWLevels { 468 | DEFAULT = 0, 469 | EXPLICIT = 1, 470 | SAFE = 2, 471 | AGE_RESTRICTED = 3, 472 | } 473 | 474 | export enum InviteTargetTypes { 475 | STREAM = 1, 476 | EMBEDDED_APPLICATION = 2, 477 | } 478 | 479 | export enum ApplicationFlags { 480 | NO_FLAGS = 0, 481 | GATEWAY_PRESENCE = 1 << 12, 482 | GATEWAY_PRESENCE_LIMITED = 1 << 13, 483 | GATEWAY_GUILD_MEMBERS = 1 << 14, 484 | GATEWAY_GUILD_MEMBERS_LIMITED = 1 << 15, 485 | VERIFICATION_PENDING_GUILD_LIMIT = 1 << 16, 486 | EMBEDDED = 1 << 17, 487 | GATEWAY_MESSAGE_CONTENT = 1 << 18, 488 | GATEWAY_MESSAGE_CONTENT_LIMITED = 1 << 19, 489 | } 490 | 491 | export enum TimestampStyles { 492 | SHORT_TIME = 't', 493 | LONG_TIME = 'T', 494 | SHORT_DATE = 'd', 495 | LONG_DATE = 'D', 496 | SHORT_DATE_TIME = 'f', 497 | LONG_DATE_TIME = 'F', 498 | RELATIVE_TIME = 'R', 499 | } 500 | 501 | export enum ThreadArchiveDurations { 502 | _1_HOUR = 60, 503 | _24_HOURS = 1440, 504 | _3_DAYS = 4320, 505 | _1_WEEK = 10080, 506 | } 507 | 508 | export enum ApplicationCommandTypes { 509 | CHAT_INPUT = 1, 510 | USER = 2, 511 | MESSAGE = 3, 512 | } 513 | 514 | export enum StickerTypes { 515 | STANDARD = 1, 516 | GUILD = 2, 517 | } 518 | 519 | export enum ScheduledEventEntityTypes { 520 | STAGE_INSTANCE = 1, 521 | VOICE = 2, 522 | EXTERNAL = 3, 523 | } 524 | 525 | export enum ScheduledEventStatuses { 526 | SCHEDULED = 1, 527 | ACTIVE = 2, 528 | COMPLETED = 3, 529 | CANCELED = 4, 530 | } 531 | 532 | export enum TextInputStyles { 533 | SHORT = 1, 534 | PARAGRAPH = 2, 535 | } 536 | 537 | export enum Locales { 538 | DANISH = 'da', 539 | GERMAN = 'de', 540 | ENGLISH_UK = 'en-GB', 541 | ENGLISH_US = 'en-US', 542 | SPANISH = 'es-ES', 543 | FRENCH = 'fr', 544 | CROATIAN = 'hr', 545 | ITALIAN = 'it', 546 | LITHUANIAN = 'lt', 547 | HUNGARIAN = 'hu', 548 | DUTCH = 'nl', 549 | NORWEGIAN = 'no', 550 | POLISH = 'pl', 551 | PORTUGUESE_BRAZILIAN = 'pt-BR', 552 | ROMANIAN_ROMANIA = 'ro', 553 | FINNISH = 'fi', 554 | SWEDISH = 'sv-SE', 555 | VIETNAMESE = 'vi', 556 | TURKISH = 'tr', 557 | CZECH = 'cs', 558 | GREEK = 'el', 559 | BULGARIAN = 'bg', 560 | RUSSIAN = 'ru', 561 | UKRAINIAN = 'uk', 562 | HINDI = 'hi', 563 | THAI = 'th', 564 | CHINESE_CHINA = 'zh-CN', 565 | JAPANESE = 'ja', 566 | CHINESE_TAIWAN = 'zh-TW', 567 | KOREAN = 'ko', 568 | } 569 | 570 | export enum ChannelFlags { 571 | NO_FLAGS = 0, 572 | PINNED = 1 << 1, 573 | } 574 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import type * as helpers from './helpers'; 2 | 3 | // Audit Log types 4 | 5 | export type AuditLog = { 6 | audit_log_entries: AuditLogEntry[]; 7 | guild_scheduled_events: ScheduledEvent[]; 8 | integrations: Integration[]; 9 | threads: Thread[]; 10 | users: User[]; 11 | webhooks: Webhook[]; 12 | }; 13 | 14 | export type AuditLogEntry = { 15 | target_id: string | null; 16 | changes?: AuditLogChangeDict[keyof AuditLogChangeDict][]; 17 | user_id: string | null; 18 | id: string; 19 | action_type: helpers.AuditLogEvents; 20 | options?: AuditEntryInfo[]; 21 | reason?: string; 22 | }; 23 | 24 | export type AuditEntryInfo = { 25 | channel_id?: string; 26 | count?: string; 27 | delete_member_days?: string; 28 | id?: number; 29 | members_removed?: string; 30 | message_id?: string; 31 | role_name?: string; 32 | type?: string; 33 | }; 34 | 35 | type AuditLogChangeDict = { 36 | [K in keyof AuditLogChangeKeys]: AuditLogChange; 37 | }; 38 | 39 | export type AuditLogChange = { 40 | new_value?: AuditLogChangeKeys[K]; 41 | old_value?: AuditLogChangeKeys[K]; 42 | key: K; 43 | }; 44 | 45 | export type AuditLogChangeKeys = { 46 | afk_channel_id: string; 47 | afk_timeout: number; 48 | allow: string; 49 | application_id: string; 50 | archived: boolean; 51 | asset: string; 52 | auto_archive_duration: helpers.ThreadArchiveDurations; 53 | available: boolean; 54 | avatar_hash: boolean; 55 | banner_hash: string; 56 | bitrate: number; 57 | channel_id: string; 58 | code: string; 59 | color: number; 60 | command_id: string; 61 | communication_disabled_until: string; 62 | deaf: boolean; 63 | default_auto_archive_duration: helpers.ThreadArchiveDurations; 64 | default_message_notifications: helpers.DefaultMessageNotificationLevels; 65 | deny: string; 66 | description: string; 67 | discovery_splash_hash: string; 68 | enable_emoticons: boolean; 69 | entity_type: helpers.ScheduledEventEntityTypes; 70 | expire_behavior: helpers.IntegrationExpireBehaviors; 71 | expire_grace_period: number; 72 | explicit_content_filter: helpers.ExplicitContentFilterLevels; 73 | format_type: helpers.MessageStickerFormatTypes; 74 | guild_id: string; 75 | hoist: boolean; 76 | icon_hash: string; 77 | image_hash: string; 78 | id: string; 79 | invitable: boolean; 80 | inviter_id: string; 81 | location: string; 82 | locked: boolean; 83 | max_age: number; 84 | max_uses: number; 85 | mentionable: boolean; 86 | mfa_level: helpers.MFA_Levels; 87 | mute: boolean; 88 | name: string; 89 | nick: string; 90 | nsfw: boolean; 91 | owner_id: string; 92 | permission_overwrites: PermissionsOverwrite[]; 93 | permissions: string; 94 | position: number; 95 | preferred_locale: helpers.Locales; 96 | privacy_level: helpers.PrivacyLevels; 97 | prune_delete_days: number; 98 | public_updates_channel_id: string; 99 | rate_limit_per_user: number; 100 | region: string; 101 | rules_channel_id: string; 102 | splash_hash: string; 103 | status: helpers.ScheduledEventStatuses; 104 | system_channel_id: string; 105 | tags: string; 106 | temporary: boolean; 107 | topic: string; 108 | type: string | number; 109 | unicode_emoji: string; 110 | user_limit: number; 111 | uses: number; 112 | vanity_url_code: string; 113 | verification_level: number; 114 | widget_channel_id: string; 115 | widget_enabled: boolean; 116 | $add: AuditLogPartialRole[]; 117 | $remove: AuditLogPartialRole[]; 118 | }; 119 | 120 | export type AuditLogPartialRole = { 121 | icon_hash: string; 122 | id: string; 123 | name: string; 124 | unicode_emoji: string; 125 | type: string; 126 | }; 127 | 128 | // Channel types 129 | 130 | export type Channel = ( 131 | | GuildChannel 132 | | DMChannel 133 | | GroupDMChannel 134 | | Thread 135 | ); 136 | 137 | export type GuildChannel = ( 138 | | GuildTextChannel 139 | | GuildCategory 140 | | GuildVoiceChannel 141 | ); 142 | 143 | export type GuildTextChannel = { 144 | id: string; 145 | type: ( 146 | | helpers.ChannelTypes.GUILD_TEXT 147 | | helpers.ChannelTypes.GUILD_NEWS 148 | | helpers.ChannelTypes.GUILD_FORUM 149 | ); 150 | guild_id: string; 151 | position: number; 152 | permission_overwrites?: PermissionsOverwrite[]; 153 | name: string; 154 | topic: string | null; 155 | nsfw: boolean; 156 | last_message_id: string | null; 157 | rate_limit_per_user: number; 158 | parent_id: string | null; 159 | last_pin_timestamp: string | null; 160 | }; 161 | 162 | export type GuildCategory = { 163 | id: string; 164 | type: helpers.ChannelTypes.GUILD_CATEGORY; 165 | guild_id: string; 166 | position: number; 167 | permission_overwrites?: PermissionsOverwrite[]; 168 | name: string; 169 | }; 170 | 171 | export type GuildVoiceChannel = { 172 | id: string; 173 | type: ( 174 | | helpers.ChannelTypes.GUILD_VOICE 175 | | helpers.ChannelTypes.GUILD_STAGE_VOICE 176 | ); 177 | guild_id: string; 178 | position: number; 179 | permission_overwrites?: PermissionsOverwrite[]; 180 | name: string; 181 | bitrate: number; 182 | user_limit: number; 183 | parent_id: string | null; 184 | rtc_region: string | null; 185 | video_quality_mode: helpers.VideoQualityModes; 186 | }; 187 | 188 | export type DMChannel = { 189 | id: string; 190 | type: helpers.ChannelTypes.DM; 191 | last_message_id: string | null; 192 | recipients: User[]; 193 | last_pin_timestamp: string | null; 194 | }; 195 | 196 | export type GroupDMChannel = { 197 | id: string; 198 | type: helpers.ChannelTypes.GROUP_DM; 199 | name: string; 200 | last_message_id: string | null; 201 | recipients: User[]; 202 | icon: string | null; 203 | owner_id: string; 204 | application_id?: string; 205 | last_pin_timestamp: string | null; 206 | }; 207 | 208 | export type Thread = { 209 | id: string; 210 | type: ( 211 | | helpers.ChannelTypes.GUILD_PUBLIC_THREAD 212 | | helpers.ChannelTypes.GUILD_PRIVATE_THREAD 213 | | helpers.ChannelTypes.GUILD_NEWS_THREAD 214 | ); 215 | guild_id: string; 216 | name: string; 217 | last_message_id: string | null; 218 | rate_limit_per_user: number; 219 | owner_id: string; 220 | parent_id: string; 221 | last_pin_timestamp: string | null; 222 | message_count: number; 223 | member_count: number; 224 | thread_metadata: ThreadMetadata; 225 | member: ThreadMember; 226 | default_auto_archive_duration: helpers.ThreadArchiveDurations; 227 | flags?: helpers.ChannelFlags; 228 | }; 229 | 230 | export type Message = { 231 | id: string; 232 | channel_id: string; 233 | guild_id?: string; 234 | author: User; 235 | member?: Omit; 236 | content: string; 237 | timestamp: string; 238 | edited_timestamp: string | null; 239 | tts: boolean; 240 | mention_everyone: boolean; 241 | mentions: (User & { member?: Omit; })[]; 242 | mention_roles: string[]; 243 | mention_channels?: ChannelMention[]; 244 | attachments: Attachment[]; 245 | embeds: Embed[]; 246 | reactions?: Reaction[]; 247 | nonce?: number | string; 248 | pinned: boolean; 249 | webhook_id?: string; 250 | type: helpers.MessageTypes; 251 | activity?: MessageActivity; 252 | application?: Application; 253 | application_id?: string; 254 | message_reference?: MessageReference; 255 | flags?: helpers.MessageFlags; 256 | referenced_message?: Message | null; 257 | interaction?: MessageInteraction; 258 | thread?: Thread; 259 | components?: ActionRow[]; 260 | sticker_items?: StickerItem[]; 261 | }; 262 | 263 | export type MessageActivity = { 264 | type: helpers.MessageActivityTypes; 265 | party_id?: string; 266 | }; 267 | 268 | export type MessageReference = { 269 | message_id?: string; 270 | channel_id: string; 271 | guild_id?: string; 272 | }; 273 | 274 | export type FollowedChannel = { 275 | channel_id: string; 276 | webhook_id: string; 277 | }; 278 | 279 | export type Reaction = { 280 | count: number; 281 | me: boolean; 282 | emoji: Omit & { 283 | name: string | null; 284 | }; 285 | }; 286 | 287 | export type PermissionsOverwrite = { 288 | id: string; 289 | type: helpers.PermissionsOverwriteTypes; 290 | allow: string; 291 | deny: string; 292 | }; 293 | 294 | export type ThreadMetadata = { 295 | archived: boolean; 296 | auto_archive_duration: helpers.ThreadArchiveDurations; 297 | archive_timestamp: string; 298 | locked: boolean; 299 | invitable?: boolean; 300 | create_timestamp?: string | null; 301 | }; 302 | 303 | export type ThreadMember = { 304 | id?: string; 305 | user_id?: string; 306 | join_timestamp: string; 307 | flags: number; 308 | }; 309 | 310 | export type Embed = { 311 | title?: string; 312 | type?: string; 313 | description?: string; 314 | url?: string; 315 | timestamp?: string; 316 | color?: number; 317 | footer?: EmbedFooter; 318 | image?: EmbedImage; 319 | thumbnail?: EmbedThumbnail; 320 | video?: EmbedVideo; 321 | provider?: EmbedProvider; 322 | author?: EmbedAuthor; 323 | fields?: EmbedField[]; 324 | }; 325 | 326 | export type EmbedThumbnail = { 327 | url: string; 328 | proxy_url?: string; 329 | height?: number; 330 | width?: number; 331 | }; 332 | 333 | export type EmbedVideo = { 334 | url: string; 335 | proxy_url?: string; 336 | height?: number; 337 | width?: number; 338 | }; 339 | 340 | export type EmbedImage = { 341 | url: string; 342 | proxy_url?: string; 343 | height?: number; 344 | width?: number; 345 | }; 346 | 347 | export type EmbedProvider = { 348 | name?: string; 349 | url?: string; 350 | }; 351 | 352 | export type EmbedAuthor = { 353 | name: string; 354 | url?: string; 355 | icon_url?: string; 356 | proxy_icon_url?: string; 357 | }; 358 | 359 | export type EmbedFooter = { 360 | text: string; 361 | icon_url?: string; 362 | proxy_icon_url?: string; 363 | }; 364 | 365 | export type EmbedField = { 366 | name: string; 367 | value: string; 368 | inline?: boolean; 369 | }; 370 | 371 | export type Attachment = { 372 | id: string; 373 | filename: string; 374 | description?: string; 375 | content_type?: string; 376 | size: number; 377 | url: string; 378 | proxy_url: string; 379 | height?: number | null; 380 | width?: number | null; 381 | ephemeral?: boolean; 382 | }; 383 | 384 | export type ChannelMention = { 385 | id: string; 386 | guild_id: string; 387 | type: number; 388 | name: string; 389 | }; 390 | 391 | export type AllowedMentions = { 392 | parse?: helpers.AllowedMentionTypes[]; 393 | roles?: string[]; 394 | users?: string[]; 395 | replied_user?: boolean; 396 | }; 397 | 398 | // Emoji types 399 | 400 | export type Emoji = { 401 | id: string | null; 402 | name: string; 403 | roles?: string[]; 404 | user?: User; 405 | require_colons?: boolean; 406 | managed?: boolean; 407 | animated?: boolean; 408 | available?: boolean; 409 | }; 410 | 411 | // Guild types 412 | 413 | export type Guild = { 414 | id: string; 415 | name: string; 416 | icon: string | null; 417 | icon_hash?: string | null; 418 | splash: string | null; 419 | discovery_splash: string | null; 420 | owner_id: string; 421 | afk_channel_id: string | null; 422 | afk_timeout: number; 423 | widget_enabled?: boolean; 424 | widget_channel_id?: string | null; 425 | verification_level: helpers.VerificationLevels; 426 | default_message_notifications: helpers.DefaultMessageNotificationLevels; 427 | explicit_content_filter: helpers.ExplicitContentFilterLevels; 428 | roles: Role[]; 429 | emojis: Emoji[]; 430 | features: helpers.GuildFeatures[]; 431 | mfa_level: helpers.MFA_Levels; 432 | application_id: string | null; 433 | system_channel_id: string | null; 434 | system_channel_flags: helpers.SystemChannelFlags; 435 | rules_channel_id: string | null; 436 | max_presences?: number | null; 437 | max_members?: number; 438 | vanity_url_code: string | null; 439 | description: string | null; 440 | banner: string | null; 441 | premium_tier: helpers.PremiumTiers; 442 | premium_subscription_count?: number; 443 | preferred_locale: helpers.Locales; 444 | public_updates_channel_id: string | null; 445 | max_video_channel_users?: number; 446 | approximate_member_count?: number; 447 | approximate_presence_count?: number; 448 | welcome_screen?: WelcomeScreen; 449 | nsfw_level: helpers.GuildNSFWLevels; 450 | stickers?: Sticker[]; 451 | premium_progress_bar_enabled: boolean; 452 | }; 453 | 454 | export type UnavailableGuild = { 455 | id: string; 456 | unavailable: boolean; 457 | }; 458 | 459 | export type GuildPreview = { 460 | id: string; 461 | name: string; 462 | icon: string | null; 463 | splash: string | null; 464 | discovery_splash: string | null; 465 | emojis: Emoji[]; 466 | features: helpers.GuildFeatures[]; 467 | approximate_member_count: number; 468 | approximate_presence_count: number; 469 | description: string | null; 470 | stickers: Sticker[]; 471 | }; 472 | 473 | export type GuildWidgetSettings = { 474 | id: string; 475 | channel_id: string | null; 476 | }; 477 | 478 | export type GuildWidget = { 479 | enabled: boolean; 480 | name: string; 481 | instant_invite: string | null; 482 | channels: GuildChannel[]; 483 | members: User[]; 484 | presence_count: number; 485 | }; 486 | 487 | export type Member = { 488 | user: User; 489 | nick?: string | null; 490 | avatar?: string | null; 491 | roles: string[]; 492 | joined_at: string; 493 | premium_since?: string | null; 494 | deaf: boolean; 495 | mute: boolean; 496 | pending?: boolean; 497 | permissions?: string; 498 | communication_disabled_until?: string | null; 499 | }; 500 | 501 | export type Integration = { 502 | id: string; 503 | name: string; 504 | type: string; 505 | enabled?: boolean; 506 | syncing?: boolean; 507 | role_id?: string; 508 | enable_emoticons?: boolean; 509 | expire_behavior?: helpers.IntegrationExpireBehaviors; 510 | expire_grace_period?: number; 511 | user?: User; 512 | account: IntegrationAccount; 513 | synced_at?: string; 514 | subscriber_count?: number; 515 | revoked?: boolean; 516 | application?: IntegrationApplication; 517 | }; 518 | 519 | export type IntegrationAccount = { 520 | id: string; 521 | name: string; 522 | }; 523 | 524 | export type IntegrationApplication = { 525 | id: string; 526 | name: string; 527 | icon: string | null; 528 | description: string; 529 | bot?: User; 530 | }; 531 | 532 | export type Ban = { 533 | reason: string | null; 534 | user: User; 535 | }; 536 | 537 | export type WelcomeScreen = { 538 | description: string | null; 539 | welcome_channels: WelcomeScreenChannel[]; 540 | }; 541 | 542 | export type WelcomeScreenChannel = { 543 | channel_id: string; 544 | description: string; 545 | emoji_id: string | null; 546 | emoji_name: string | null; 547 | }; 548 | 549 | // Invite types 550 | 551 | export type Invite = { 552 | code: string; 553 | guild?: Guild; 554 | channel: GuildChannel | null; 555 | inviter?: User; 556 | target_type?: helpers.InviteTargetTypes; 557 | target_user?: User; 558 | target_application?: Application; 559 | approximate_presence_count?: number; 560 | approximate_member_count?: number; 561 | expires_at?: string | null; 562 | guild_scheduled_event?: ScheduledEvent; 563 | }; 564 | 565 | export type InviteMetadata = { 566 | uses: number; 567 | max_uses: number; 568 | max_age: number; 569 | temporary: boolean; 570 | created_at: string; 571 | }; 572 | 573 | // Template types 574 | 575 | export type Template = { 576 | code: string; 577 | name: string; 578 | description: string | null; 579 | usage_count: number; 580 | creator_id: string; 581 | creator: User; 582 | created_at: string; 583 | updated_at: string; 584 | source_guild_id: string; 585 | serialized_source_guild: Guild; 586 | is_dirty: boolean | null; 587 | }; 588 | 589 | // User types 590 | 591 | export type User = { 592 | id: string; 593 | username: string; 594 | discriminator: string; 595 | avatar: string | null; 596 | bot?: boolean; 597 | system?: boolean; 598 | mfa_enabled?: boolean; 599 | banner?: string | null; 600 | accent_color?: number | null; 601 | locale?: helpers.Locales; 602 | verified?: boolean; 603 | email?: string | null; 604 | flags?: helpers.UserFlags; 605 | premium_type?: helpers.PremiumTypes; 606 | public_flags?: helpers.UserFlags; 607 | }; 608 | 609 | export type Connection = { 610 | id: string; 611 | name: string; 612 | type: string; 613 | revoked?: boolean; 614 | integrations?: Integration[]; 615 | verified: boolean; 616 | friend_sync: boolean; 617 | show_activity: boolean; 618 | visibility: helpers.VisibilityTypes; 619 | }; 620 | 621 | // Role types 622 | 623 | export type Role = { 624 | id: string; 625 | name: string; 626 | color: number; 627 | hoist: boolean; 628 | icon?: string | null; 629 | unicode_emoji?: string | null; 630 | position: number; 631 | permissions: string; 632 | managed: boolean; 633 | mentionable: boolean; 634 | tags?: RoleTags; 635 | }; 636 | 637 | export type RoleTags = { 638 | bot_id?: string; 639 | integration_id?: string; 640 | premium_subscriber?: boolean | null; 641 | }; 642 | 643 | // Voice types 644 | 645 | export type VoiceState = { 646 | guild_id?: string; 647 | channel_id: string | null; 648 | user_id: string; 649 | member?: Member; 650 | session_id: string; 651 | deaf: boolean; 652 | mute: boolean; 653 | self_deaf: boolean; 654 | self_mute: boolean; 655 | self_stream?: boolean; 656 | self_video: boolean; 657 | suppress: boolean; 658 | request_to_speak_timestamp: string | null; 659 | }; 660 | 661 | export type VoiceRegion = { 662 | id: string; 663 | name: string; 664 | optimal: boolean; 665 | deprecated: boolean; 666 | custom: boolean; 667 | }; 668 | 669 | // Webhook types 670 | 671 | export type Webhook = { 672 | id: string; 673 | type: helpers.WebhookTypes; 674 | guild_id?: string; 675 | channel_id: string; 676 | user?: User; 677 | name: string | null; 678 | avatar: string | null; 679 | token?: string; 680 | application_id: string | null; 681 | source_guild?: Guild; 682 | source_channel?: GuildChannel; 683 | url?: string; 684 | } & ({ 685 | type: helpers.WebhookTypes.INCOMING; 686 | token: string; 687 | } | { 688 | token?: undefined; 689 | }) & ({ 690 | type: helpers.WebhookTypes.CHANNEL_FOLLOWER; 691 | source_guild: Guild; 692 | source_channel: GuildChannel; 693 | } | { 694 | source_guild?: undefined; 695 | source_channel?: undefined; 696 | }); 697 | 698 | // Application commands types 699 | 700 | export type ApplicationCommandBase = { 701 | type: helpers.ApplicationCommandTypes; 702 | name: string; 703 | name_localizations?: LocaleDictionary | null; 704 | description?: string; 705 | description_localizations?: LocaleDictionary | null; 706 | options?: ApplicationCommandOption[]; 707 | default_member_permissions?: string | null; 708 | dm_permission?: boolean; 709 | } & ({ 710 | type: helpers.ApplicationCommandTypes.CHAT_INPUT; 711 | description: string; 712 | } | { 713 | description?: ''; 714 | options?: undefined; 715 | }); 716 | 717 | export type ApplicationCommand = { 718 | id: string; 719 | application_id: string; 720 | guild_id?: string; 721 | default_member_permissions: string | null; 722 | version: string; 723 | } & ApplicationCommandBase; 724 | 725 | export type ApplicationCommandOption = { 726 | type: helpers.ApplicationCommandOptionTypes; 727 | name: string; 728 | name_localizations?: LocaleDictionary | null; 729 | description: string; 730 | description_localizations?: LocaleDictionary | null; 731 | required?: boolean; 732 | choices?: ApplicationCommandOptionChoice[]; 733 | options?: ApplicationCommandOption[]; 734 | channel_types?: helpers.ChannelTypes[]; 735 | min_value?: number; 736 | max_value?: number; 737 | autocomplete?: boolean; 738 | } & ({ 739 | type: helpers.ApplicationCommandOptionTypes.STRING; 740 | choices?: ApplicationCommandOptionChoice[]; 741 | options?: undefined; 742 | channel_types?: undefined; 743 | min_value?: undefined; 744 | max_value?: undefined; 745 | } | { 746 | type: ( 747 | | helpers.ApplicationCommandOptionTypes.INTEGER 748 | | helpers.ApplicationCommandOptionTypes.NUMBER 749 | ); 750 | choices?: ApplicationCommandOptionChoice[]; 751 | options?: undefined; 752 | channel_types?: undefined; 753 | } | { 754 | type: helpers.ApplicationCommandOptionTypes.SUB_COMMAND; 755 | required?: undefined; 756 | choices?: undefined; 757 | options?: (ApplicationCommandOption & { 758 | type: Exclude; 762 | })[]; 763 | channel_types?: undefined; 764 | min_value?: undefined; 765 | max_value?: undefined; 766 | autocomplete?: undefined; 767 | } | { 768 | type: helpers.ApplicationCommandOptionTypes.SUB_COMMAND_GROUP; 769 | required?: undefined; 770 | choices?: undefined; 771 | options: (ApplicationCommandOption & { 772 | type: helpers.ApplicationCommandOptionTypes.SUB_COMMAND; 773 | })[]; 774 | channel_types?: undefined; 775 | min_value?: undefined; 776 | max_value?: undefined; 777 | autocomplete?: undefined; 778 | } | { 779 | type: helpers.ApplicationCommandOptionTypes.CHANNEL; 780 | choices?: undefined; 781 | options?: undefined; 782 | min_value?: undefined; 783 | max_value?: undefined; 784 | autocomplete?: undefined; 785 | } | { 786 | choices?: undefined; 787 | options?: undefined; 788 | channel_types?: undefined; 789 | min_value?: undefined; 790 | max_value?: undefined; 791 | autocomplete?: undefined; 792 | }) & ({ 793 | choices: ApplicationCommandOptionChoice[]; 794 | autocomplete?: false; 795 | min_value?: undefined; 796 | max_value?: undefined; 797 | } | { 798 | choices?: undefined; 799 | }); 800 | 801 | export type ApplicationCommandOptionChoice = { 802 | name: string; 803 | name_localizations?: LocaleDictionary | null; 804 | value: T; 805 | }; 806 | 807 | export type GuildApplicationCommandPermissions = { 808 | id: string; 809 | application_id: string; 810 | guild_id: string; 811 | permissions: ApplicationCommandPermissions[]; 812 | }; 813 | 814 | export type ApplicationCommandPermissions = { 815 | id: string; 816 | type: helpers.ApplicationCommandPermissionTypes; 817 | permission: boolean; 818 | }; 819 | 820 | export type LocaleDictionary = { 821 | [key in helpers.Locales]?: string; 822 | }; 823 | 824 | // Interaction types 825 | 826 | export type Interaction = { 827 | id: string; 828 | application_id: string; 829 | type: helpers.InteractionTypes; 830 | data?: ( 831 | | InteractionData 832 | | InteractionDataComponent 833 | | InteractionDataModal 834 | ); 835 | guild_id?: string; 836 | channel_id?: string; 837 | member?: Member; 838 | user?: User; 839 | token: string; 840 | version: number; 841 | message?: Message; 842 | locale?: helpers.Locales; 843 | guild_locale?: helpers.Locales; 844 | } & ({ 845 | type: ( 846 | | helpers.InteractionTypes.APPLICATION_COMMAND 847 | | helpers.InteractionTypes.APPLICATION_COMMAND_AUTOCOMPLETE 848 | ); 849 | data: InteractionData; 850 | } | { 851 | type: helpers.InteractionTypes.MESSAGE_COMPONENT; 852 | data: InteractionDataComponent; 853 | } | { 854 | type: helpers.InteractionTypes.MODAL_SUBMIT; 855 | data: InteractionDataModal; 856 | } | { 857 | data?: undefined; 858 | }) & ({ 859 | guild_id: string; 860 | member: Member; 861 | user?: undefined; 862 | guild_locale: helpers.Locales; 863 | } | { 864 | guild_id?: undefined; 865 | member?: undefined; 866 | user: User; 867 | guild_locale?: undefined; 868 | }) & ({ 869 | type: helpers.InteractionTypes.PING; 870 | locale?: undefined; 871 | } | { 872 | locale: helpers.Locales; 873 | }); 874 | 875 | export type InteractionData = { 876 | id: string; 877 | name: string; 878 | type: helpers.ApplicationCommandTypes; 879 | resolved?: InteractionDataResolved; 880 | options?: InteractionDataOption[]; 881 | guild_id?: string; 882 | target_id?: string; 883 | } & ({ 884 | type: helpers.ApplicationCommandTypes.CHAT_INPUT; 885 | options: InteractionDataOption[]; 886 | target_id?: undefined; 887 | } | { 888 | options?: undefined; 889 | target_id: string; 890 | }); 891 | 892 | export type InteractionDataComponent = { 893 | custom_id: string; 894 | component_type: helpers.ComponentTypes; 895 | values?: SelectOption[]; 896 | } & ({ 897 | component_type: helpers.ComponentTypes.SELECT_MENU; 898 | values: SelectOption[]; 899 | } | { 900 | values?: undefined; 901 | }); 902 | 903 | export type InteractionDataModal = { 904 | custom_id: string; 905 | components: TextInput[]; 906 | }; 907 | 908 | export type InteractionDataResolved = { 909 | users?: { 910 | [id: string]: User; 911 | }; 912 | members?: { 913 | [id: string]: Omit; 918 | }; 919 | roles?: { 920 | [id: string]: Role; 921 | }; 922 | channels?: { 923 | [id: string]: { 924 | id: string; 925 | type: helpers.ChannelTypes; 926 | name?: string; 927 | thread_metadata?: ThreadMetadata; 928 | parent_id?: string | null; 929 | permissions?: string; 930 | }; 931 | }; 932 | messages?: { 933 | [id: string]: Message; 934 | }; 935 | attachments?: { 936 | [id: string]: Attachment; 937 | }; 938 | }; 939 | 940 | export type InteractionDataOption = { 941 | name: string; 942 | type: helpers.ApplicationCommandOptionTypes; 943 | value?: string | number | boolean; 944 | options?: InteractionDataOption[]; 945 | focused?: boolean; 946 | } & ({ 947 | type: ( 948 | | helpers.ApplicationCommandOptionTypes.STRING 949 | | helpers.ApplicationCommandOptionTypes.USER 950 | | helpers.ApplicationCommandOptionTypes.CHANNEL 951 | | helpers.ApplicationCommandOptionTypes.ROLE 952 | | helpers.ApplicationCommandOptionTypes.MENTIONABLE 953 | | helpers.ApplicationCommandOptionTypes.ATTACHMENT 954 | ); 955 | value: string; 956 | options?: undefined; 957 | } | { 958 | type: ( 959 | | helpers.ApplicationCommandOptionTypes.INTEGER 960 | | helpers.ApplicationCommandOptionTypes.NUMBER 961 | ); 962 | value: number; 963 | options?: undefined; 964 | } | { 965 | type: helpers.ApplicationCommandOptionTypes.BOOLEAN; 966 | value: boolean; 967 | options?: undefined; 968 | } | { 969 | type: ( 970 | | helpers.ApplicationCommandOptionTypes.SUB_COMMAND 971 | | helpers.ApplicationCommandOptionTypes.SUB_COMMAND_GROUP 972 | ); 973 | value?: undefined; 974 | options: InteractionDataOption[]; 975 | }); 976 | 977 | export type MessageInteraction = { 978 | id: string; 979 | type: helpers.InteractionTypes; 980 | name: string; 981 | user: User; 982 | member?: Omit; 983 | }; 984 | 985 | export type InteractionResponse = { 986 | type: helpers.InteractionCallbackTypes; 987 | data: ( 988 | | InteractionCallbackData 989 | | InteractionAutocompleteCallbackData 990 | | InteractionModalCallbackData 991 | ); 992 | } & ({ 993 | type: ( 994 | | helpers.InteractionCallbackTypes.CHANNEL_MESSAGE_WITH_SOURCE 995 | | helpers.InteractionCallbackTypes.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE 996 | | helpers.InteractionCallbackTypes.DEFERRED_UPDATE_MESSAGE 997 | | helpers.InteractionCallbackTypes.UPDATE_MESSAGE 998 | ); 999 | data: InteractionCallbackData; 1000 | } | { 1001 | type: helpers.InteractionCallbackTypes.APPLICATION_COMMAND_AUTOCOMPLETE_RESULT; 1002 | data: InteractionAutocompleteCallbackData; 1003 | } | { 1004 | type: helpers.InteractionCallbackTypes.MODAL; 1005 | data: InteractionModalCallbackData; 1006 | }); 1007 | 1008 | export type InteractionCallbackData = { 1009 | tts?: boolean; 1010 | content?: string; 1011 | embeds?: Embed[]; 1012 | allowed_mentions?: AllowedMentions; 1013 | flags?: helpers.MessageFlags; 1014 | components?: ActionRow[]; 1015 | attachments?: Attachment[]; 1016 | }; 1017 | 1018 | export type InteractionAutocompleteCallbackData = { 1019 | choices: ApplicationCommandOptionChoice[]; 1020 | }; 1021 | 1022 | export type InteractionModalCallbackData = { 1023 | custom_id: string; 1024 | title: string; 1025 | components: TextInput[]; 1026 | }; 1027 | 1028 | // Gateway types 1029 | 1030 | export type Presence = { 1031 | user: { id: string; }; 1032 | guild_id?: string; 1033 | status?: helpers.StatusTypes; 1034 | activities?: Activity[]; 1035 | client_status?: ClientStatus; 1036 | }; 1037 | 1038 | export type Activity = { 1039 | name: string; 1040 | type: helpers.ActivityTypes; 1041 | url?: string | null; 1042 | created_at: number; 1043 | timestamps?: ActivityTimestamps; 1044 | application_id?: string; 1045 | details?: string | null; 1046 | state?: string | null; 1047 | emoji?: ActivityEmoji; 1048 | party?: ActivityParty; 1049 | assets?: ActivityAssets; 1050 | secrets?: ActivitySecrets; 1051 | instance?: boolean; 1052 | flags?: helpers.ActivityFlags; 1053 | }; 1054 | 1055 | export type ActivityTimestamps = { 1056 | start?: number; 1057 | end?: number; 1058 | }; 1059 | 1060 | export type ActivityEmoji = { 1061 | name: string; 1062 | id?: string; 1063 | animated?: boolean; 1064 | }; 1065 | 1066 | export type ActivityParty = { 1067 | id?: string; 1068 | size?: [number, number]; 1069 | }; 1070 | 1071 | export type ActivityAssets = { 1072 | large_image?: string; 1073 | large_text?: string; 1074 | small_image?: string; 1075 | small_text?: string; 1076 | }; 1077 | 1078 | export type ActivitySecrets = { 1079 | join?: string; 1080 | spectate?: string; 1081 | match?: string; 1082 | }; 1083 | 1084 | export type ClientStatus = { 1085 | desktop?: string; 1086 | mobile?: string; 1087 | web?: string; 1088 | }; 1089 | 1090 | export type SessionStartLimit = { 1091 | total: number; 1092 | remaining: number; 1093 | reset_after: number; 1094 | max_concurrency: number; 1095 | }; 1096 | 1097 | // OAuth2 types 1098 | 1099 | export type Application = { 1100 | id: string; 1101 | name: string; 1102 | icon: string | null; 1103 | description: string; 1104 | rpc_origins?: string[]; 1105 | bot_public: boolean; 1106 | bot_require_code_grant: boolean; 1107 | terms_of_service_url?: string; 1108 | privacy_policy_url?: string; 1109 | owner?: User; 1110 | verify_key: string; 1111 | team: Team | null; 1112 | guild_id?: string; 1113 | primary_sku_id?: string; 1114 | slug?: string; 1115 | cover_image?: string; 1116 | flags?: helpers.ApplicationFlags; 1117 | tags?: string[]; 1118 | install_params?: InstallParams; 1119 | custom_install_url?: string; 1120 | }; 1121 | 1122 | export type Team = { 1123 | icon: string | null; 1124 | id: string; 1125 | members: TeamMember[]; 1126 | owner_user_id: string; 1127 | }; 1128 | 1129 | export type TeamMember = { 1130 | membership_state: helpers.MembershipStates; 1131 | permissions: string[]; 1132 | team_id: string; 1133 | user: User; 1134 | }; 1135 | 1136 | export type InstallParams = { 1137 | scopes: string[]; 1138 | permissions: string; 1139 | }; 1140 | 1141 | // Message Components types 1142 | 1143 | export type ActionRow = { 1144 | type: helpers.ComponentTypes.ACTION_ROW; 1145 | components: ( 1146 | | Button 1147 | | SelectMenu 1148 | )[]; 1149 | }; 1150 | 1151 | export type Button = { 1152 | type: helpers.ComponentTypes.BUTTON; 1153 | style: helpers.ButtonStyles; 1154 | label?: string; 1155 | emoji?: Pick; 1160 | custom_id?: string; 1161 | url?: string; 1162 | disabled?: boolean; 1163 | } & ({ 1164 | style: helpers.ButtonStyles.LINK; 1165 | custom_id?: undefined; 1166 | url: string; 1167 | } | { 1168 | custom_id: string; 1169 | url?: undefined; 1170 | }); 1171 | 1172 | export type SelectMenu = { 1173 | type: helpers.ComponentTypes.SELECT_MENU; 1174 | custom_id: string; 1175 | options: SelectOption[]; 1176 | placeholder?: string; 1177 | min_values: number; 1178 | max_values: number; 1179 | disabled?: boolean; 1180 | }; 1181 | 1182 | export type SelectOption = { 1183 | label: string; 1184 | value: string; 1185 | description?: string; 1186 | emoji?: Pick; 1191 | default?: boolean; 1192 | }; 1193 | 1194 | export type TextInput = { 1195 | type: helpers.ComponentTypes.TEXT_INPUT; 1196 | custom_id: string; 1197 | style: helpers.TextInputStyles; 1198 | label: string; 1199 | min_length?: number; 1200 | max_length?: number; 1201 | required?: boolean; 1202 | value?: string; 1203 | placeholder?: string; 1204 | }; 1205 | 1206 | // Stage Instance types 1207 | 1208 | export type StageInstance = { 1209 | id: string; 1210 | guild_id: string; 1211 | channel_id: string; 1212 | topic: string; 1213 | privacy_level: helpers.PrivacyLevels; 1214 | guild_scheduled_event_id: string | null; 1215 | }; 1216 | 1217 | // Sticker types 1218 | 1219 | export type Sticker = { 1220 | id: string; 1221 | pack_id?: string; 1222 | name: string; 1223 | description: string | null; 1224 | tags: string; 1225 | type: helpers.StickerTypes; 1226 | format_type: helpers.MessageStickerFormatTypes; 1227 | available?: boolean; 1228 | guild_id?: string; 1229 | user?: User; 1230 | sort_value?: number; 1231 | } & ({ 1232 | type: helpers.StickerTypes.STANDARD; 1233 | pack_id: string; 1234 | available?: undefined; 1235 | guild_id?: undefined; 1236 | user?: undefined; 1237 | sort_value: number; 1238 | } | { 1239 | type: helpers.StickerTypes.GUILD; 1240 | pack_id?: undefined; 1241 | available: boolean; 1242 | guild_id: string; 1243 | sort_value?: undefined; 1244 | }); 1245 | 1246 | export type StickerItem = { 1247 | id: string; 1248 | name: string; 1249 | format_type: helpers.MessageStickerFormatTypes; 1250 | }; 1251 | 1252 | export type StickerPack = { 1253 | id: string; 1254 | stickers: Sticker[]; 1255 | name: string; 1256 | sku_id: string; 1257 | cover_sticker_id?: string; 1258 | description: string; 1259 | banner_asset_id?: string; 1260 | }; 1261 | 1262 | // Guild Scheduled Event types 1263 | 1264 | export type ScheduledEvent = { 1265 | id: string; 1266 | guild_id: string; 1267 | channel_id: string | null; 1268 | creator_id: string | null; 1269 | name: string; 1270 | description?: string | null; 1271 | scheduled_start_time: string; 1272 | scheduled_end_time: string | null; 1273 | privacy_level: helpers.PrivacyLevels; 1274 | status: helpers.ScheduledEventStatuses; 1275 | entity_type: helpers.ScheduledEventEntityTypes; 1276 | entity_id: string | null; 1277 | entity_metadata: ScheduledEventEntityMetadata | null; 1278 | creator?: ScheduledEventUser; 1279 | user_count?: number; 1280 | image?: string | null; 1281 | }; 1282 | 1283 | export type ScheduledEventEntityMetadata = { 1284 | location?: string; 1285 | }; 1286 | 1287 | export type ScheduledEventUser = { 1288 | guild_scheduled_event_id: string; 1289 | user: User; 1290 | member?: Member; 1291 | }; 1292 | --------------------------------------------------------------------------------