feat: Add @discordjs/core (#8736)

* feat: add @discordjs/core

* chore: lint

* chore: add all gateway events

* chore: add the rest of the rest routes

* chore: cleanup gateway

* chore: rename gateway to client

* chore: rename gateway to client

* fix: don't spread unless we need to

* refactor: use classes and make requested changes

* chore: show shardId on emit

* chore: add interface for intrinsic props

* refactor: scope dispatch data instead of spreading

* chore: add utility for uploading files for messages and interactions

* feat: finish up form data handling

* chore: add readme

* chore: update api-extractor stuff

* chore: bump deps

* chore: make requested changes

* chore: make requested changes

* Update package.json

* chore: make requested changes

* fix: add missing interaction responses

* chore: make some requested changes

* chore: remove `return await`

* chore: use autoModeration instead of automod

* refactor: use snowflakes and -types results

* chore: sort imports, fix return type on editUserVoiceState

* chore: rename bots to users

* feat: add automod dispatch events

* refactor: move templates and members into guild

* fix: use users instead of bots in api class

* chore: imports

* chore: make requested changes

* fix: don't make files required on interaction replies

* fix: rename sendMessage to createMessage

* feat: add application command routes

* feat: add webhook.execute overloads and options to invites.get

* chore: use create prefixes

* chore: seperate interaction params

* chore: use Id

* chore: make requested changes

* chore: make requested changes

* chore: make requested changes

* chore: for -> from

* Apply suggestions from code review

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>

* Update packages/core/README.md

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>

* chore: make requested changes

* chore: update -types

* chore: bump vitest

* fix: sticker uploading

* fix: lockfile

* chore: make requested changes

* chore: make requested changes

* Update packages/core/src/api/applicationCommands.ts

Co-authored-by: Almeida <almeidx@pm.me>

* Apply suggestions from code review

Co-authored-by: Aura Román <kyradiscord@gmail.com>

* Update packages/core/README.md

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>

Co-authored-by: almeidx <almeidx@pm.me>
Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
Co-authored-by: Aura Román <kyradiscord@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
Suneet Tipirneni 2022-11-27 16:23:13 -05:00 committed by GitHub
parent 12553da135
commit 2127b32d26
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 2979 additions and 2 deletions

3
.github/labeler.yml vendored
View file

@ -14,6 +14,9 @@ packages:builders:
packages:collection:
- packages/collection/*
- packages/collection/**/*
packages/core:
- packages:core/*
- packages:core/**/*
packages:discord.js:
- packages/discord.js/*
- packages/discord.js/**/*

2
.github/labels.yml vendored
View file

@ -56,6 +56,8 @@
color: fbca04
- name: packages:collection
color: fbca04
- name: packages:core
color: fbca04
- name: packages:discord.js
color: fbca04
- name: packages:docgen

View file

@ -0,0 +1,5 @@
{
"name": "core",
"org": "discordjs",
"packagePath": "packages/core"
}

View file

@ -0,0 +1,6 @@
{
"extends": "../../.eslintrc.json",
"rules": {
"jsdoc/check-param-names": "off"
}
}

27
packages/core/.gitignore vendored Normal file
View file

@ -0,0 +1,27 @@
# Packages
node_modules/
# Log files
logs/
*.log
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
# Env
.env
# Dist
dist/
typings/
docs/**/*
!docs/index.json
!docs/README.md
# Miscellaneous
.tmp/
coverage/
tsconfig.tsbuildinfo

View file

@ -0,0 +1 @@
module.exports = require('../../.lintstagedrc.json');

View file

@ -0,0 +1,8 @@
# Autogenerated
CHANGELOG.md
.turbo
dist/
docs/**/*
!docs/index.yml
!docs/README.md
coverage/

View file

@ -0,0 +1 @@
module.exports = require('../../.prettierrc.json');

191
packages/core/LICENSE Normal file
View file

@ -0,0 +1,191 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2022 Noel Buechler
Copyright 2022 Suneet Tipirneni
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

115
packages/core/README.md Normal file
View file

@ -0,0 +1,115 @@
<div align="center">
<br />
<p>
<a href="https://discord.js.org"><img src="https://discord.js.org/static/logo.svg" width="546" alt="discord.js" /></a>
</p>
<br />
<p>
<a href="https://discord.gg/djs"><img src="https://img.shields.io/discord/222078108977594368?color=5865F2&logo=discord&logoColor=white" alt="Discord server" /></a>
<a href="https://www.npmjs.com/package/@discordjs/core"><img src="https://img.shields.io/npm/v/@discordjs/core.svg?maxAge=3600" alt="npm version" /></a>
<a href="https://www.npmjs.com/package/@discordjs/core"><img src="https://img.shields.io/npm/dt/@discordjs/core.svg?maxAge=3600" alt="npm downloads" /></a>
<a href="https://github.com/discordjs/discord.js/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Build status" /></a>
<a href="https://codecov.io/gh/discordjs/discord.js" ><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=core" alt="Code coverage" /></a>
</p>
<p>
<a href="https://vercel.com/?utm_source=discordjs&utm_campaign=oss"><img src="https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg" alt="Vercel" /></a>
</p>
</div>
## About
`@discordjs/core` is a thinly abstracted wrapper around the "core" components of the Discord API: REST, and gateway.
## Installation
**Node.js 16.9.0 or newer is required.**
```sh-session
npm install @discordjs/core
yarn add @discordjs/core
pnpm add @discordjs/core
```
## Example usage
```ts
import { REST } from '@discordjs/rest';
import { WebSocketManager } from '@discordjs/ws';
import { GatewayIntentBits, InteractionType, MessageFlags, createClient } from '@discordjs/core';
// Create REST and WebSocket managers directly
const rest = new REST({ version: '10' }).setToken(token);
const ws = new WebSocketManager({
token,
intents: GatewayIntentBits.GuildMessages | GatewayIntentBits.MessageContent,
rest,
});
// Create a client to emit relevant events.
const client = createClient({ rest, ws });
// Listen for interactions
// Each event contains an `api` prop along with the event data that allows you to interface with the Discord REST API
client.on('interactionCreate', async ({ interaction, api }) => {
if (!(interaction.type === InteractionType.ApplicationCommand) || interaction.data.name !== 'ping') {
return;
}
await api.interactions.reply(interaction.id, interaction.token, { content: 'Pong!', flags: MessageFlags.Ephemeral });
});
// Listen for the ready event
client.on('ready', () => console.log('Ready!'));
// Start the WebSocket connection.
ws.connect();
```
## Independent REST API Usage
```ts
// Create REST instance
const rest = new REST({ version: '10' }).setToken(token);
// Pass into API
const api = new API(rest);
// Fetch a guild using the API wrapper
const guild = await api.guilds.get('1234567891011');
```
## Links
- [Website][website] ([source][website-source])
- [Documentation][documentation]
- [Guide][guide] ([source][guide-source])
See also the [Update Guide][guide-update], including updated and removed items in the library.
- [discord.js Discord server][discord]
- [Discord API Discord server][discord-api]
- [GitHub][source]
- [npm][npm]
- [Related libraries][related-libs]
## Contributing
Before creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the
[documentation][documentation].
See [the contribution guide][contributing] if you'd like to submit a PR.
## Help
If you don't understand something in the documentation, you are experiencing problems, or you just need a gentle
nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].
[website]: https://discord.js.org/
[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website
[documentation]: https://discord.js.org/
[guide]: https://discordjs.guide/
[guide-source]: https://github.com/discordjs/guide
[guide-update]: https://discordjs.guide/additional-info/changes-in-v14.html
[discord]: https://discord.gg/djs
[discord-api]: https://discord.gg/discord-api
[source]: https://github.com/discordjs/discord.js/tree/main/packages/core
[npm]: https://www.npmjs.com/package/@discordjs/core
[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries
[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md

View file

@ -0,0 +1,3 @@
{
"extends": "../../api-extractor.json"
}

63
packages/core/cliff.toml Normal file
View file

@ -0,0 +1,63 @@
[changelog]
header = """
# Changelog
All notable changes to this project will be documented in this file.\n
"""
body = """
{% if version %}\
# [{{ version | trim_start_matches(pat="v") }}]\
{% if previous %}\
{% if previous.version %}\
(https://github.com/discordjs/discord.js/compare/{{ previous.version }}...{{ version }})\
{% else %}\
(https://github.com/discordjs/discord.js/tree/{{ version }})\
{% endif %}\
{% endif %} \
- ({{ timestamp | date(format="%Y-%m-%d") }})
{% else %}\
# [unreleased]
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
## {{ group | upper_first }}
{% for commit in commits %}
- {% if commit.scope %}\
**{{commit.scope}}:** \
{% endif %}\
{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}](https://github.com/discordjs/discord.js/commit/{{ commit.id }}))\
{% if commit.breaking %}\
{% for breakingChange in commit.footers %}\
\n{% raw %} {% endraw %}- **{{ breakingChange.token }}{{ breakingChange.separator }}** {{ breakingChange.value }}\
{% endfor %}\
{% endif %}\
{% endfor %}
{% endfor %}\n
"""
trim = true
footer = ""
[git]
conventional_commits = true
filter_unconventional = true
commit_parsers = [
{ message = "^feat", group = "Features"},
{ message = "^fix", group = "Bug Fixes"},
{ message = "^docs", group = "Documentation"},
{ message = "^perf", group = "Performance"},
{ message = "^refactor", group = "Refactor"},
{ message = "^typings", group = "Typings"},
{ message = "^types", group = "Typings"},
{ message = ".*deprecated", body = ".*deprecated", group = "Deprecation"},
{ message = "^revert", skip = true},
{ message = "^style", group = "Styling"},
{ message = "^test", group = "Testing"},
{ message = "^chore", skip = true},
{ message = "^ci", skip = true},
{ message = "^build", skip = true},
{ body = ".*security", group = "Security"},
]
filter_commits = true
tag_pattern = "@discordjs/core@[0-9]*"
ignore_tags = ""
date_order = true
sort_commits = "newest"

View file

@ -0,0 +1,73 @@
{
"name": "@discordjs/core",
"version": "0.1.0",
"description": "A thinly abstracted wrapper around the rest API, and gateway.",
"scripts": {
"test": "vitest run",
"build": "tsup",
"lint": "prettier --check . && cross-env TIMING=1 eslint src --ext .mjs,.js,.ts --format=pretty",
"format": "prettier --write . && cross-env TIMING=1 eslint src --ext .mjs,.js,.ts --fix --format=pretty",
"docs": "api-extractor run --local",
"prepack": "yarn build && yarn lint",
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/core/*'",
"release": "cliff-jumper"
},
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"typings": "./dist/index.d.ts",
"exports": {
"import": "./dist/index.mjs",
"require": "./dist/index.js",
"types": "./dist/index.d.ts"
},
"directories": {
"lib": "src",
"test": "__tests__"
},
"files": [
"dist"
],
"contributors": [
"Crawl <icrawltogo@gmail.com>",
"SpaceEEC <spaceeec@yahoo.com>",
"Vlad Frangu <kingdgrizzle@gmail.com>",
"Aura Román <kyradiscord@gmail.com>",
"Suneet Tipirneni <suneettipirneni@icloud.com>"
],
"license": "Apache-2.0",
"keywords": [],
"repository": {
"type": "git",
"url": "git+https://github.com/discordjs/discord.js.git"
},
"bugs": {
"url": "https://github.com/discordjs/discord.js/issues"
},
"homepage": "https://discord.js.org",
"dependencies": {
"@discordjs/rest": "workspace:^",
"@discordjs/ws": "workspace:^",
"@vladfrangu/async_event_emitter": "^2.1.2",
"discord-api-types": "^0.37.20"
},
"devDependencies": {
"@favware/cliff-jumper": "^1.9.0",
"@microsoft/api-extractor": "^7.33.6",
"@types/node": "16.18.3",
"@vitest/coverage-c8": "^0.25.3",
"cross-env": "^7.0.3",
"eslint": "^8.28.0",
"eslint-config-neon": "^0.1.40",
"eslint-formatter-pretty": "^4.1.0",
"prettier": "^2.8.0",
"tsup": "^6.5.0",
"typescript": "^4.9.3",
"vitest": "^0.25.3"
},
"engines": {
"node": ">=16.9.0"
},
"publishConfig": {
"access": "public"
}
}

View file

@ -0,0 +1,240 @@
import { makeURLSearchParams, type REST } from '@discordjs/rest';
import {
Routes,
type RESTGetAPIApplicationCommandPermissionsResult,
type RESTGetAPIApplicationCommandResult,
type RESTGetAPIApplicationCommandsResult,
type RESTGetAPIGuildApplicationCommandsPermissionsResult,
type RESTPatchAPIApplicationCommandJSONBody,
type RESTPatchAPIApplicationCommandResult,
type RESTPostAPIApplicationCommandsJSONBody,
type RESTPostAPIApplicationCommandsResult,
type RESTPutAPIApplicationCommandPermissionsJSONBody,
type RESTPutAPIApplicationCommandPermissionsResult,
type RESTPutAPIApplicationCommandsJSONBody,
type RESTGetAPIApplicationCommandsQuery,
type RESTPutAPIApplicationCommandsResult,
type RESTGetAPIApplicationGuildCommandsQuery,
type Snowflake,
} from 'discord-api-types/v10';
export class ApplicationCommandsAPI {
public constructor(private readonly rest: REST) {}
/**
* Fetches all global commands for a application
*
* @param applicationId - The application id to fetch commands for
* @param options - The options to use when fetching commands
*/
public async getGlobalCommands(applicationId: Snowflake, options: RESTGetAPIApplicationCommandsQuery = {}) {
return this.rest.get(Routes.applicationCommands(applicationId), {
query: makeURLSearchParams(options as Record<string, unknown>),
}) as Promise<RESTGetAPIApplicationCommandsResult>;
}
/**
* Creates a new global command
*
* @param applicationId - The application id to create the command for
* @param data - The data to use when creating the command
*/
public async createGlobalCommand(applicationId: Snowflake, data: RESTPostAPIApplicationCommandsJSONBody) {
return this.rest.post(Routes.applicationCommands(applicationId), {
body: data,
}) as Promise<RESTPostAPIApplicationCommandsResult>;
}
/**
* Fetches a global command
*
* @param applicationId - The application id to fetch the command from
* @param commandId - The command id to fetch
*/
public async getGlobalCommand(applicationId: Snowflake, commandId: Snowflake) {
return this.rest.get(
Routes.applicationCommand(applicationId, commandId),
) as Promise<RESTGetAPIApplicationCommandResult>;
}
/**
* Edits a global command
*
* @param applicationId - The application id of the command
* @param commandId - The id of the command to edit
* @param data - The data to use when editing the command
*/
public async editGlobalCommand(
applicationId: Snowflake,
commandId: Snowflake,
data: RESTPatchAPIApplicationCommandJSONBody,
) {
return this.rest.patch(Routes.applicationCommand(applicationId, commandId), {
body: data,
}) as Promise<RESTPatchAPIApplicationCommandResult>;
}
/**
* Deletes a global command
*
* @param applicationId - The application id of the command
* @param commandId - The id of the command to delete
*/
public async deleteGlobalCommand(applicationId: Snowflake, commandId: Snowflake) {
await this.rest.delete(Routes.applicationCommand(applicationId, commandId));
}
/**
* Overwrites global commands
*
* @param applicationId - The application id to overwrite commands for
* @param data - The data to use when overwriting commands
*/
public async bulkOverwriteGlobalCommands(applicationId: Snowflake, data: RESTPutAPIApplicationCommandsJSONBody) {
return this.rest.put(Routes.applicationCommands(applicationId), {
body: data,
}) as Promise<RESTPutAPIApplicationCommandsResult>;
}
/**
* Fetches all commands for a guild
*
* @param applicationId - The application id to fetch commands for
* @param guildId - The guild id to fetch commands for
* @param data - The data to use when fetching commands
*/
public async getGuildCommands(
applicationId: Snowflake,
guildId: Snowflake,
data: RESTGetAPIApplicationGuildCommandsQuery = {},
) {
return this.rest.get(Routes.applicationGuildCommands(applicationId, guildId), {
query: makeURLSearchParams(data as Record<string, unknown>),
}) as Promise<RESTGetAPIApplicationCommandsResult>;
}
/**
* Creates a new command for a guild
*
* @param applicationId - The application id to create the command for
* @param guildId - The guild id to create the command for
* @param data - The data to use when creating the command
*/
public async createGuildCommand(
applicationId: Snowflake,
guildId: Snowflake,
data: RESTPostAPIApplicationCommandsJSONBody,
) {
return this.rest.post(Routes.applicationGuildCommands(applicationId, guildId), {
body: data,
}) as Promise<RESTPostAPIApplicationCommandsResult>;
}
/**
* Fetches a guild command
*
* @param applicationId - The application id to fetch the command from
* @param guildId - The guild id to fetch the command from
* @param commandId - The command id to fetch
*/
public async getGuildCommand(applicationId: Snowflake, guildId: Snowflake, commandId: Snowflake) {
return this.rest.get(
Routes.applicationGuildCommand(applicationId, guildId, commandId),
) as Promise<RESTGetAPIApplicationCommandResult>;
}
/**
* Edits a guild command
*
* @param applicationId - The application id of the command
* @param guildId - The guild id of the command
* @param commandId - The command id to edit
* @param data - The data to use when editing the command
*/
public async editGuildCommand(
applicationId: Snowflake,
guildId: Snowflake,
commandId: Snowflake,
data: RESTPatchAPIApplicationCommandJSONBody,
) {
return this.rest.patch(Routes.applicationGuildCommand(applicationId, guildId, commandId), {
body: data,
}) as Promise<RESTPatchAPIApplicationCommandResult>;
}
/**
* Deletes a guild command
*
* @param applicationId - The application id of the command
* @param guildId - The guild id of the command
* @param commandId - The id of the command to delete
*/
public async deleteGuildCommand(applicationId: Snowflake, guildId: Snowflake, commandId: Snowflake) {
await this.rest.delete(Routes.applicationGuildCommand(applicationId, guildId, commandId));
}
/**
* Bulk overwrites guild commands
*
* @param applicationId - The application id to overwrite commands for
* @param guildId - The guild id to overwrite commands for
* @param data - The data to use when overwriting commands
*/
public async bulkOverwriteGuildCommands(
applicationId: Snowflake,
guildId: Snowflake,
data: RESTPutAPIApplicationCommandsJSONBody,
) {
return this.rest.put(Routes.applicationGuildCommands(applicationId, guildId), {
body: data,
}) as Promise<RESTPutAPIApplicationCommandsResult>;
}
/**
* Fetches the permissions for a guild command
*
* @param applicationId - The application id to get the permissions for
* @param guildId - The guild id of the command
* @param commandId - The command id to get the permissions for
*/
public async getGuildCommandPermissions(applicationId: Snowflake, guildId: Snowflake, commandId: Snowflake) {
return this.rest.get(
Routes.applicationCommandPermissions(applicationId, guildId, commandId),
) as Promise<RESTGetAPIApplicationCommandPermissionsResult>;
}
/**
* Fetches all permissions for all commands in a guild
*
* @param applicationId - The application id to get the permissions for
* @param guildId - The guild id to get the permissions for
*/
public async getGuildCommandsPermissions(applicationId: Snowflake, guildId: Snowflake) {
return this.rest.get(
Routes.guildApplicationCommandsPermissions(applicationId, guildId),
) as Promise<RESTGetAPIGuildApplicationCommandsPermissionsResult>;
}
/**
* Edits the permissions for a guild command
*
* @param userToken - The token of the user to edit permissions on behalf of
* @param applicationId - The application id to edit the permissions for
* @param guildId - The guild id to edit the permissions for
* @param commandId - The id of the command to edit the permissions for
* @param data - The data to use when editing the permissions
*/
public async editGuildCommandPermissions(
userToken: string,
applicationId: Snowflake,
guildId: Snowflake,
commandId: Snowflake,
data: RESTPutAPIApplicationCommandPermissionsJSONBody,
) {
return this.rest.put(Routes.applicationCommandPermissions(applicationId, guildId, commandId), {
headers: { Authorization: `Bearer ${userToken.replace('Bearer ', '')}` },
auth: false,
body: data,
}) as Promise<RESTPutAPIApplicationCommandPermissionsResult>;
}
}

View file

@ -0,0 +1,326 @@
import { makeURLSearchParams, type RawFile, type REST } from '@discordjs/rest';
import {
Routes,
type RESTDeleteAPIChannelResult,
type RESTGetAPIChannelInvitesResult,
type RESTGetAPIChannelMessageReactionUsersQuery,
type RESTGetAPIChannelMessageReactionUsersResult,
type RESTGetAPIChannelMessageResult,
type RESTGetAPIChannelMessagesQuery,
type RESTGetAPIChannelMessagesResult,
type RESTGetAPIChannelPinsResult,
type RESTGetAPIChannelResult,
type RESTGetAPIChannelThreadsArchivedQuery,
type RESTGetAPIChannelUsersThreadsArchivedResult,
type RESTPatchAPIChannelJSONBody,
type RESTPatchAPIChannelMessageResult,
type RESTPatchAPIChannelResult,
type RESTPostAPIChannelFollowersResult,
type RESTPostAPIChannelInviteJSONBody,
type RESTPostAPIChannelInviteResult,
type RESTPostAPIChannelMessageCrosspostResult,
type RESTPostAPIChannelMessageJSONBody,
type RESTPostAPIChannelMessageResult,
type Snowflake,
} from 'discord-api-types/v10';
export class ChannelsAPI {
public constructor(private readonly rest: REST) {}
/**
* Sends a message in a channel
*
* @param channelId - The id of the channel to send the message in
* @param data - The data to use when sending the message
*/
public async createMessage(
channelId: Snowflake,
{ files, ...body }: RESTPostAPIChannelMessageJSONBody & { files?: RawFile[] },
) {
return this.rest.post(Routes.channelMessages(channelId), {
files,
body,
}) as Promise<RESTPostAPIChannelMessageResult>;
}
/**
* Edits a message
*
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to edit
* @param data - The data to use when editing the message
*/
public async editMessage(
channelId: Snowflake,
messageId: Snowflake,
{ files, ...body }: RESTPostAPIChannelMessageJSONBody & { files?: RawFile[] },
) {
return this.rest.patch(Routes.channelMessage(channelId, messageId), {
files,
body,
}) as Promise<RESTPatchAPIChannelMessageResult>;
}
/**
* Fetches the reactions for a message
*
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to get the reactions for
* @param emoji - The emoji to get the reactions for
* @param options - The options to use when fetching the reactions
*/
public async getMessageReactions(
channelId: Snowflake,
messageId: Snowflake,
emoji: string,
options: RESTGetAPIChannelMessageReactionUsersQuery = {},
) {
return this.rest.get(Routes.channelMessageReaction(channelId, messageId, encodeURIComponent(emoji)), {
query: makeURLSearchParams(options as Record<string, unknown>),
}) as Promise<RESTGetAPIChannelMessageReactionUsersResult>;
}
/**
* Deletes a reaction for the current user
*
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to delete the reaction for
* @param emoji - The emoji to delete the reaction for
*/
public async deleteOwnMessageReaction(channelId: Snowflake, messageId: Snowflake, emoji: string) {
await this.rest.delete(Routes.channelMessageOwnReaction(channelId, messageId, encodeURIComponent(emoji)));
}
/**
* Deletes a reaction for a user
*
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to delete the reaction for
* @param emoji - The emoji to delete the reaction for
* @param userId - The id of the user to delete the reaction for
*/
public async deleteUserMessageReaction(channelId: Snowflake, messageId: Snowflake, emoji: string, userId: Snowflake) {
await this.rest.delete(Routes.channelMessageUserReaction(channelId, messageId, encodeURIComponent(emoji), userId));
}
/**
* Deletes all reactions for a message
*
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to delete the reactions for
*/
public async deleteAllMessageReactions(channelId: Snowflake, messageId: Snowflake) {
await this.rest.delete(Routes.channelMessageAllReactions(channelId, messageId));
}
/**
* Deletes all reactions of an emoji for a message
*
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to delete the reactions for
* @param emoji - The emoji to delete the reactions for
*/
public async deleteAllMessageReactionsForEmoji(channelId: Snowflake, messageId: Snowflake, emoji: string) {
await this.rest.delete(Routes.channelMessageReaction(channelId, messageId, encodeURIComponent(emoji)));
}
/**
* Adds a reaction to a message
*
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to add the reaction to
* @param emoji - The emoji to add the reaction with
*/
public async addMessageReaction(channelId: Snowflake, messageId: Snowflake, emoji: string) {
await this.rest.put(Routes.channelMessageOwnReaction(channelId, messageId, encodeURIComponent(emoji)));
}
/**
* Fetches a channel
*
* @param channelId - The id of the channel
*/
public async get(channelId: Snowflake) {
return this.rest.get(Routes.channel(channelId)) as Promise<RESTGetAPIChannelResult>;
}
/**
* Edits a channel
*
* @param channelId - The id of the channel to edit
* @param data - The new channel data
*/
public async edit(channelId: Snowflake, data: RESTPatchAPIChannelJSONBody) {
return this.rest.patch(Routes.channel(channelId), { body: data }) as Promise<RESTPatchAPIChannelResult>;
}
/**
* Deletes a channel
*
* @param channelId - The id of the channel to delete
*/
public async delete(channelId: Snowflake) {
return this.rest.delete(Routes.channel(channelId)) as Promise<RESTDeleteAPIChannelResult>;
}
/**
* Fetches the messages of a channel
*
* @param channelId - The id of the channel to fetch messages from
* @param options - The options to use when fetching messages
*/
public async getMessages(channelId: Snowflake, options: RESTGetAPIChannelMessagesQuery = {}) {
return this.rest.get(Routes.channelMessages(channelId), {
query: makeURLSearchParams(options as Record<string, unknown>),
}) as Promise<RESTGetAPIChannelMessagesResult>;
}
/**
* Shows a typing indicator in a channel
*
* @param channelId - The id of the channel to show the typing indicator in
*/
public async showTyping(channelId: Snowflake) {
await this.rest.post(Routes.channelTyping(channelId));
}
/**
* Fetches the pinned messages of a channel
*
* @param channelId - The id of the channel to fetch pinned messages from
*/
public async getPins(channelId: Snowflake) {
return this.rest.get(Routes.channelPins(channelId)) as Promise<RESTGetAPIChannelPinsResult>;
}
/**
* Pins a message in a channel
*
* @param channelId - The id of the channel to pin the message in
* @param messageId - The id of the message to pin
* @param reason - The reason for pinning the message
*/
public async pinMessage(channelId: Snowflake, messageId: Snowflake, reason?: string) {
await this.rest.put(Routes.channelPin(channelId, messageId), { reason });
}
/**
* Deletes a message
*
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to delete
* @param reason - The reason for deleting the message
*/
public async deleteMessage(channelId: Snowflake, messageId: Snowflake, reason?: string) {
await this.rest.delete(Routes.channelMessage(channelId, messageId), { reason });
}
/**
* Bulk deletes messages
*
* @param channelId - The id of the channel the messages are in
* @param messageIds - The ids of the messages to delete
*/
public async bulkDeleteMessages(channelId: Snowflake, messageIds: Snowflake[], reason?: string): Promise<void> {
await this.rest.post(Routes.channelBulkDelete(channelId), { reason, body: { messages: messageIds } });
}
/**
* Fetches a message
*
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to fetch
*/
public async getMessage(channelId: Snowflake, messageId: Snowflake) {
return this.rest.get(Routes.channelMessage(channelId, messageId)) as Promise<RESTGetAPIChannelMessageResult>;
}
/**
* Crossposts a message
*
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to crosspost
*/
public async crosspostMessage(channelId: Snowflake, messageId: Snowflake) {
return this.rest.post(
Routes.channelMessageCrosspost(channelId, messageId),
) as Promise<RESTPostAPIChannelMessageCrosspostResult>;
}
/**
* Unpins a message in a channel
*
* @param channelId - The id of the channel to unpin the message in
* @param messageId - The id of the message to unpin
* @param reason - The reason for unpinning the message
*/
public async unpinMessage(channelId: Snowflake, messageId: Snowflake, reason?: string) {
await this.rest.delete(Routes.channelPin(channelId, messageId), { reason });
}
/**
* Follows an announcement channel
*
* @param channelId - The id of the announcement channel to follow
* @param webhookChannelId - The id of the webhook channel to follow the announcements in
*/
public async followAnnouncements(channelId: Snowflake, webhookChannelId: Snowflake) {
return this.rest.post(Routes.channelFollowers(channelId), {
body: { webhook_channel_id: webhookChannelId },
}) as Promise<RESTPostAPIChannelFollowersResult>;
}
/**
* Creates a new invite for a channel
*
* @param channelId - The id of the channel to create an invite for
* @param data - The data to use when creating the invite
*/
public async createInvite(channelId: Snowflake, data: RESTPostAPIChannelInviteJSONBody, reason?: string) {
return this.rest.post(Routes.channelInvites(channelId), {
reason,
body: data,
}) as Promise<RESTPostAPIChannelInviteResult>;
}
/**
* Fetches the invites of a channel
*
* @param channelId - The id of the channel to fetch invites from
*/
public async getInvites(channelId: Snowflake) {
return this.rest.get(Routes.channelInvites(channelId)) as Promise<RESTGetAPIChannelInvitesResult>;
}
/**
* Fetches the archived threads of a channel
*
* @param channelId - The id of the channel to fetch archived threads from
* @param archivedStatus - The archived status of the threads to fetch
* @param options - The options to use when fetching archived threads
*/
public async getArchivedThreads(
channelId: Snowflake,
archivedStatus: 'private' | 'public',
options: RESTGetAPIChannelThreadsArchivedQuery = {},
) {
return this.rest.get(Routes.channelThreads(channelId, archivedStatus), {
query: makeURLSearchParams(options as Record<string, unknown>),
}) as Promise<RESTGetAPIChannelUsersThreadsArchivedResult>;
}
/**
* Fetches the private joined archived threads of a channel
*
* @param channelId - The id of the channel to fetch joined archived threads from
* @param options - The options to use when fetching joined archived threads
*/
public async getJoinedPrivateArchivedThreads(
channelId: Snowflake,
options: RESTGetAPIChannelThreadsArchivedQuery = {},
) {
return this.rest.get(Routes.channelJoinedArchivedThreads(channelId), {
query: makeURLSearchParams(options as Record<string, unknown>),
}) as Promise<RESTGetAPIChannelUsersThreadsArchivedResult>;
}
}

View file

@ -0,0 +1,901 @@
import type { RawFile } from '@discordjs/rest';
import { makeURLSearchParams, type REST } from '@discordjs/rest';
import {
Routes,
type GuildMFALevel,
type GuildWidgetStyle,
type RESTGetAPIAuditLogQuery,
type RESTGetAPIAuditLogResult,
type RESTGetAPIAutoModerationRuleResult,
type RESTGetAPIAutoModerationRulesResult,
type RESTGetAPIGuildBansResult,
type RESTGetAPIGuildChannelsResult,
type RESTGetAPIGuildEmojiResult,
type RESTGetAPIGuildEmojisResult,
type RESTGetAPIGuildIntegrationsResult,
type RESTGetAPIGuildInvitesResult,
type RESTGetAPIGuildMemberResult,
type RESTGetAPIGuildMembersQuery,
type RESTGetAPIGuildMembersSearchResult,
type RESTGetAPIGuildPreviewResult,
type RESTGetAPIGuildPruneCountResult,
type RESTGetAPIGuildResult,
type RESTGetAPIGuildRolesResult,
type RESTGetAPIGuildScheduledEventQuery,
type RESTGetAPIGuildScheduledEventResult,
type RESTGetAPIGuildScheduledEventsQuery,
type RESTGetAPIGuildScheduledEventsResult,
type RESTGetAPIGuildScheduledEventUsersQuery,
type RESTGetAPIGuildScheduledEventUsersResult,
type RESTGetAPIGuildStickerResult,
type RESTGetAPIGuildStickersResult,
type RESTGetAPIGuildTemplatesResult,
type RESTGetAPIGuildThreadsResult,
type RESTGetAPIGuildVanityUrlResult,
type RESTGetAPIGuildVoiceRegionsResult,
type RESTGetAPIGuildPruneCountQuery,
type RESTPostAPIGuildStickerFormDataBody,
type RESTPostAPIGuildStickerResult,
type RESTGetAPIGuildMembersSearchQuery,
type RESTGetAPIGuildWelcomeScreenResult,
type RESTGetAPIGuildWidgetImageResult,
type RESTGetAPIGuildWidgetJSONResult,
type RESTGetAPITemplateResult,
type RESTPatchAPIAutoModerationRuleJSONBody,
type RESTPatchAPIGuildChannelPositionsJSONBody,
type RESTPatchAPIGuildEmojiJSONBody,
type RESTPatchAPIGuildEmojiResult,
type RESTPatchAPIGuildJSONBody,
type RESTPatchAPIGuildMemberJSONBody,
type RESTPatchAPIGuildMemberResult,
type RESTPatchAPIGuildResult,
type RESTPatchAPIGuildRoleJSONBody,
type RESTPatchAPIGuildRolePositionsJSONBody,
type RESTPatchAPIGuildRolePositionsResult,
type RESTPatchAPIGuildRoleResult,
type RESTPatchAPIGuildScheduledEventJSONBody,
type RESTPatchAPIGuildScheduledEventResult,
type RESTPatchAPIGuildStickerJSONBody,
type RESTPatchAPIGuildStickerResult,
type RESTPatchAPIGuildTemplateJSONBody,
type RESTPatchAPIGuildTemplateResult,
type RESTPatchAPIGuildVoiceStateUserJSONBody,
type RESTPatchAPIGuildWelcomeScreenJSONBody,
type RESTPatchAPIGuildWelcomeScreenResult,
type RESTPatchAPIGuildWidgetSettingsJSONBody,
type RESTPatchAPIGuildWidgetSettingsResult,
type RESTPostAPIAutoModerationRuleJSONBody,
type RESTPostAPIAutoModerationRuleResult,
type RESTPostAPIGuildChannelJSONBody,
type RESTPostAPIGuildChannelResult,
type RESTPostAPIGuildEmojiJSONBody,
type RESTPostAPIGuildEmojiResult,
type RESTPostAPIGuildPruneJSONBody,
type RESTPostAPIGuildRoleJSONBody,
type RESTPostAPIGuildRoleResult,
type RESTPostAPIGuildScheduledEventJSONBody,
type RESTPostAPIGuildScheduledEventResult,
type RESTPostAPIGuildsJSONBody,
type RESTPostAPIGuildsMFAResult,
type RESTPostAPIGuildsResult,
type RESTPostAPIGuildTemplatesResult,
type RESTPostAPITemplateCreateGuildJSONBody,
type RESTPutAPIGuildBanJSONBody,
type RESTPutAPIGuildTemplateSyncResult,
type Snowflake,
} from 'discord-api-types/v10';
export class GuildsAPI {
public constructor(private readonly rest: REST) {}
/**
* Fetches a guild
*
* @param guildId - The id of the guild
*/
public async get(guildId: string) {
return this.rest.get(Routes.guild(guildId)) as Promise<RESTGetAPIGuildResult>;
}
/**
* Fetches a guild preview
*
* @param guildId - The id of the guild to fetch the preview from
*/
public async getPreview(guildId: Snowflake) {
return this.rest.get(Routes.guildPreview(guildId)) as Promise<RESTGetAPIGuildPreviewResult>;
}
/**
* Creates a guild
*
* @param data - The guild to create
*/
public async create(data: RESTPostAPIGuildsJSONBody) {
return this.rest.post(Routes.guilds(), { body: data }) as Promise<RESTPostAPIGuildsResult>;
}
/**
* Edits a guild
*
* @param guildId - The id of the guild to edit
* @param data - The new guild data
* @param reason - The reason for editing this guild
*/
public async edit(guildId: Snowflake, data: RESTPatchAPIGuildJSONBody, reason?: string) {
return this.rest.patch(Routes.guild(guildId), { reason, body: data }) as Promise<RESTPatchAPIGuildResult>;
}
/**
* Deletes a guild
*
* @param guildId - The id of the guild to delete
* @param reason - The reason for deleting this guild
*/
public async delete(guildId: Snowflake, reason?: string) {
await this.rest.delete(Routes.guild(guildId), { reason });
}
/**
* Fetches all the members of a guild
*
* @param guildId - The id of the guild
* @param options - The options to use when fetching the guild members
*/
public async getMembers(guildId: Snowflake, options: RESTGetAPIGuildMembersQuery = {}) {
return this.rest.get(Routes.guildMembers(guildId), {
query: makeURLSearchParams(options as Record<string, unknown>),
}) as Promise<RESTGetAPIGuildMemberResult>;
}
/**
* Fetches a guild's channels
*
* @param guildId - The id of the guild to fetch the channels from
*/
public async getChannels(guildId: Snowflake) {
return this.rest.get(Routes.guildChannels(guildId)) as Promise<RESTGetAPIGuildChannelsResult>;
}
/**
* Creates a guild channel
*
* @param guildId - The id of the guild to create the channel in
* @param data - The data to create the new channel
* @param reason - The reason for creating this channel
*/
public async createChannel(guildId: Snowflake, data: RESTPostAPIGuildChannelJSONBody, reason?: string) {
return this.rest.post(Routes.guildChannels(guildId), {
reason,
body: data,
}) as Promise<RESTPostAPIGuildChannelResult>;
}
/**
* Edits a guild channel's positions
*
* @param guildId - The id of the guild to edit the channel positions from
* @param data - The data to edit the channel positions with
* @param reason - The reason for editing the channel positions
*/
public async setChannelPositions(
guildId: Snowflake,
data: RESTPatchAPIGuildChannelPositionsJSONBody,
reason?: string,
) {
await this.rest.patch(Routes.guildChannels(guildId), { reason, body: data });
}
/**
* Fetches the active threads in a guild
*
* @param guildId - The id of the guild to fetch the active threads from
*/
public async getActiveThreads(guildId: Snowflake) {
return this.rest.get(Routes.guildActiveThreads(guildId)) as Promise<RESTGetAPIGuildThreadsResult>;
}
/**
* Fetches a guild member ban
*
* @param guildId - The id of the guild to fetch the ban from
*/
public async getMemberBans(guildId: Snowflake) {
return this.rest.get(Routes.guildBans(guildId)) as Promise<RESTGetAPIGuildBansResult>;
}
/**
* Bans a user from a guild
*
* @param guildId - The id of the guild to ban the member in
* @param userId - The id of the user to ban
* @param options - Options for banning the user
* @param reason - The reason for banning the user
*/
public async banUser(
guildId: Snowflake,
userId: Snowflake,
options: RESTPutAPIGuildBanJSONBody = {},
reason?: string,
) {
await this.rest.put(Routes.guildBan(guildId, userId), { reason, body: options });
}
/**
* Unbans a user from a guild
*
* @param guildId - The id of the guild to unban the member in
* @param userId - The id of the user to unban
* @param reason - The reason for unbanning the user
*/
public async unbanUser(guildId: Snowflake, userId: Snowflake, reason?: string) {
await this.rest.delete(Routes.guildBan(guildId, userId), { reason });
}
/**
* Gets all the roles in a guild
*
* @param guildId - The id of the guild to fetch the roles from
*/
public async getRoles(guildId: Snowflake) {
return this.rest.get(Routes.guildRoles(guildId)) as Promise<RESTGetAPIGuildRolesResult>;
}
/**
* Creates a guild role
*
* @param guildId - The id of the guild to create the role in
* @param data - The data to create the role with
* @param reason - The reason for creating the role
*/
public async createRole(guildId: Snowflake, data: RESTPostAPIGuildRoleJSONBody, reason?: string) {
return this.rest.post(Routes.guildRoles(guildId), { reason, body: data }) as Promise<RESTPostAPIGuildRoleResult>;
}
/**
* Sets role positions in a guild
*
* @param guildId - The id of the guild to set role positions for
* @param data - The data for setting a role position
* @param reason - The reason for setting the role position
*/
public async setRolePositions(guildId: Snowflake, data: RESTPatchAPIGuildRolePositionsJSONBody, reason?: string) {
return this.rest.patch(Routes.guildRoles(guildId), {
reason,
body: data,
}) as Promise<RESTPatchAPIGuildRolePositionsResult>;
}
/**
* Edits a guild role
*
* @param guildId - The id of the guild to edit the role in
* @param roleId - The id of the role to edit
* @param data - data for editing the role
* @param reason - The reason for editing the role
*/
public async editRole(guildId: Snowflake, roleId: Snowflake, data: RESTPatchAPIGuildRoleJSONBody, reason?: string) {
return this.rest.patch(Routes.guildRole(guildId, roleId), {
reason,
body: data,
}) as Promise<RESTPatchAPIGuildRoleResult>;
}
/**
* Deletes a guild role
*
* @param guildId - The id of the guild to delete the role in
* @param roleId - The id of the role to delete
* @param reason - The reason for deleting the role
*/
public async deleteRole(guildId: Snowflake, roleId: Snowflake, reason?: string) {
await this.rest.delete(Routes.guildRole(guildId, roleId), { reason });
}
/**
* Edits the multi-factor-authentication (MFA) level of a guild
*
* @param guildId - The id of the guild to edit the MFA level for
* @param level - The new MFA level
* @param reason - The reason for editing the MFA level
*/
public async editMFALevel(guildId: Snowflake, level: GuildMFALevel, reason?: string) {
return this.rest.post(Routes.guildMFA(guildId), {
reason,
body: { mfa_level: level },
}) as Promise<RESTPostAPIGuildsMFAResult>;
}
/**
* Fetch the number of members that can be pruned from a guild
*
* @param guildId - The id of the guild to fetch the number of pruned members from
* @param options - The options for fetching the number of pruned members
*/
public async getPruneCount(guildId: Snowflake, options: RESTGetAPIGuildPruneCountQuery = {}) {
return this.rest.get(Routes.guildPrune(guildId), {
query: makeURLSearchParams(options as Record<string, unknown>),
}) as Promise<RESTGetAPIGuildPruneCountResult>;
}
/**
* Prunes members in a guild
*
* @param guildId - The id of the guild to prune members in
* @param options - The options for pruning members
* @param reason - The reason for pruning members
*/
public async beginPrune(guildId: Snowflake, options: RESTPostAPIGuildPruneJSONBody = {}, reason?: string) {
return this.rest.post(Routes.guildPrune(guildId), {
body: options,
reason,
}) as Promise<RESTGetAPIGuildPruneCountResult>;
}
/**
* Fetches voice regions for a guild
*
* @param guildId - The id of the guild to fetch the voice regions from
*/
public async getVoiceRegions(guildId: Snowflake) {
return this.rest.get(Routes.guildVoiceRegions(guildId)) as Promise<RESTGetAPIGuildVoiceRegionsResult>;
}
/**
* Fetches the invites for a guild
*
* @param guildId - The id of the guild to fetch the invites from
*/
public async getInvites(guildId: Snowflake) {
return this.rest.get(Routes.guildInvites(guildId)) as Promise<RESTGetAPIGuildInvitesResult>;
}
/**
* Fetches the integrations for a guild
*
* @param guildId - The id of the guild to fetch the integrations from
*/
public async getIntegrations(guildId: Snowflake) {
return this.rest.get(Routes.guildIntegrations(guildId)) as Promise<RESTGetAPIGuildIntegrationsResult>;
}
/**
* Deletes an integration from a guild
*
* @param guildId - The id of the guild to delete the integration from
* @param integrationId - The id of the integration to delete
* @param reason - The reason for deleting the integration
*/
public async deleteIntegration(guildId: Snowflake, integrationId: Snowflake, reason?: string) {
await this.rest.delete(Routes.guildIntegration(guildId, integrationId), { reason });
}
/**
* Fetches the widget settings for a guild
*
* @param guildId - The id of the guild to fetch the widget settings from
*/
public async getWidgetSettings(guildId: Snowflake) {
return this.rest.get(Routes.guildWidgetSettings(guildId)) as Promise<RESTGetAPIGuildWidgetImageResult>;
}
/**
* Edits the widget settings for a guild
*
* @param guildId - The id of the guild to edit the widget settings from
* @param data - The new widget settings data
* @param reason - The reason for editing the widget settings
*/
public async editWidgetSettings(guildId: Snowflake, data: RESTPatchAPIGuildWidgetSettingsJSONBody, reason?: string) {
return this.rest.patch(Routes.guildWidgetSettings(guildId), {
reason,
body: data,
}) as Promise<RESTPatchAPIGuildWidgetSettingsResult>;
}
/**
* Fetches the widget for a guild
*
* @param guildId - The id of the guild to fetch the widget from
*/
public async getWidget(guildId: Snowflake) {
return this.rest.get(Routes.guildWidgetJSON(guildId)) as Promise<RESTGetAPIGuildWidgetJSONResult>;
}
/**
* Fetches the vanity url for a guild
*
* @param guildId - The id of the guild to fetch the vanity url from
*/
public async getVanityURL(guildId: Snowflake) {
return this.rest.get(Routes.guildVanityUrl(guildId)) as Promise<RESTGetAPIGuildVanityUrlResult>;
}
/**
* Fetches the widget image for a guild
*
* @param guildId - The id of the guild to fetch the widget image from
* @param style - The style of the widget image
*/
public async getWidgetImage(guildId: Snowflake, style?: GuildWidgetStyle) {
return this.rest.get(Routes.guildWidgetImage(guildId), {
query: makeURLSearchParams({ style }),
}) as Promise<RESTGetAPIGuildWidgetImageResult>;
}
/**
* Fetches the welcome screen for a guild
*
* @param guildId - The id of the guild to fetch the welcome screen from
*/
public async getWelcomeScreen(guildId: Snowflake) {
return this.rest.get(Routes.guildWelcomeScreen(guildId)) as Promise<RESTGetAPIGuildWelcomeScreenResult>;
}
/**
* Edits the welcome screen for a guild
*
* @param guildId - The id of the guild to edit the welcome screen for
* @param data - The new welcome screen data
* @param reason - The reason for editing the welcome screen
*/
public async editWelcomeScreen(guildId: Snowflake, data?: RESTPatchAPIGuildWelcomeScreenJSONBody, reason?: string) {
return this.rest.patch(Routes.guildWelcomeScreen(guildId), {
reason,
body: data,
}) as Promise<RESTPatchAPIGuildWelcomeScreenResult>;
}
/**
* Edits a user's voice state in a guild
*
* @param guildId - The id of the guild to edit the current user's voice state in
* @param userId - The id of the user to edit the voice state for
* @param data - The data for editing the voice state
* @param reason - The reason for editing the voice state
*/
public async editUserVoiceState(
guildId: Snowflake,
userId: Snowflake,
data: RESTPatchAPIGuildVoiceStateUserJSONBody,
reason?: string,
) {
await this.rest.patch(Routes.guildVoiceState(guildId, userId), { reason, body: data });
}
/**
* Fetches all emojis for a guild
*
* @param guildId - The id of the guild to fetch the emojis from
*/
public async getEmojis(guildId: Snowflake) {
return this.rest.get(Routes.guildEmojis(guildId)) as Promise<RESTGetAPIGuildEmojisResult>;
}
/**
* Fetches an emoji for a guild
*
* @param guildId - The id of the guild to fetch the emoji from
* @param emojiId - The id of the emoji to fetch
*/
public async getEmoji(guildId: Snowflake, emojiId: Snowflake) {
return this.rest.get(Routes.guildEmoji(guildId, emojiId)) as Promise<RESTGetAPIGuildEmojiResult>;
}
/**
* Creates a new emoji for a guild
*
* @param guildId - The id of the guild to create the emoji from
* @param data - The data for creating the emoji
* @param reason - The reason for creating the emoji
*/
public async createEmoji(guildId: Snowflake, data: RESTPostAPIGuildEmojiJSONBody, reason?: string) {
return this.rest.post(Routes.guildEmojis(guildId), {
reason,
body: data,
}) as Promise<RESTPostAPIGuildEmojiResult>;
}
/**
* Edits an emoji for a guild
*
* @param guildId - The id of the guild to edit the emoji from
* @param emojiId - The id of the emoji to edit
* @param data - The data for editing the emoji
* @param reason - The reason for editing the emoji
*/
public async editEmoji(
guildId: Snowflake,
emojiId: Snowflake,
data: RESTPatchAPIGuildEmojiJSONBody,
reason?: string,
) {
return this.rest.patch(Routes.guildEmoji(guildId, emojiId), {
reason,
body: data,
}) as Promise<RESTPatchAPIGuildEmojiResult>;
}
/**
* Deletes an emoji for a guild
*
* @param guildId - The id of the guild to delete the emoji from
* @param emojiId - The id of the emoji to delete
* @param reason - The reason for deleting the emoji
*/
public async deleteEmoji(guildId: Snowflake, emojiId: Snowflake, reason?: string) {
await this.rest.delete(Routes.guildEmoji(guildId, emojiId), { reason });
}
/**
* Fetches all scheduled events for a guild
*
* @param guildId - The id of the guild to fetch the scheduled events from
* @param options - The options for fetching the scheduled events
*/
public async getScheduledEvents(guildId: Snowflake, options: RESTGetAPIGuildScheduledEventsQuery = {}) {
return this.rest.get(Routes.guildScheduledEvents(guildId), {
query: makeURLSearchParams(options as Record<string, unknown>),
}) as Promise<RESTGetAPIGuildScheduledEventsResult>;
}
/**
* Creates a new scheduled event for a guild
*
* @param guildId - The id of the guild to create the scheduled event from
* @param data - The data to create the event with
* @param reason - The reason for creating the scheduled event
*/
public async createScheduledEvent(guildId: Snowflake, data: RESTPostAPIGuildScheduledEventJSONBody, reason?: string) {
return this.rest.post(Routes.guildScheduledEvents(guildId), {
reason,
body: data,
}) as Promise<RESTPostAPIGuildScheduledEventResult>;
}
/**
* Fetches a scheduled event for a guild
*
* @param guildId - The id of the guild to fetch the scheduled event from
* @param eventId - The id of the scheduled event to fetch
* @param options - The options for fetching the scheduled event
*/
public async getScheduledEvent(
guildId: Snowflake,
eventId: Snowflake,
options: RESTGetAPIGuildScheduledEventQuery = {},
) {
return this.rest.get(Routes.guildScheduledEvent(guildId, eventId), {
query: makeURLSearchParams(options as Record<string, unknown>),
}) as Promise<RESTGetAPIGuildScheduledEventResult>;
}
/**
* Edits a scheduled event for a guild
*
* @param guildId - The id of the guild to edit the scheduled event from
* @param eventId - The id of the scheduled event to edit
* @param data - The new event data
* @param reason - The reason for editing the scheduled event
*/
public async editScheduledEvent(
guildId: Snowflake,
eventId: Snowflake,
data: RESTPatchAPIGuildScheduledEventJSONBody,
reason?: string,
) {
return this.rest.patch(Routes.guildScheduledEvent(guildId, eventId), {
reason,
body: data,
}) as Promise<RESTPatchAPIGuildScheduledEventResult>;
}
/**
* Deletes a scheduled event for a guild
*
* @param guildId - The id of the guild to delete the scheduled event from
* @param eventId - The id of the scheduled event to delete
* @param reason - The reason for deleting the scheduled event
*/
public async deleteScheduledEvent(guildId: Snowflake, eventId: Snowflake, reason?: string) {
await this.rest.delete(Routes.guildScheduledEvent(guildId, eventId), { reason });
}
/**
* Gets all users that are interested in a scheduled event
*
* @param guildId - The id of the guild to fetch the scheduled event users from
* @param eventId - The id of the scheduled event to fetch the users for
* @param options - The options for fetching the scheduled event users
*/
public async getScheduledEventUsers(
guildId: Snowflake,
eventId: Snowflake,
options: RESTGetAPIGuildScheduledEventUsersQuery = {},
) {
return this.rest.get(Routes.guildScheduledEventUsers(guildId, eventId), {
query: makeURLSearchParams(options as Record<string, unknown>),
}) as Promise<RESTGetAPIGuildScheduledEventUsersResult>;
}
/**
* Fetches all the templates for a guild
*
* @param guildId - The id of the guild to fetch the templates from
*/
public async getTemplates(guildId: Snowflake) {
return this.rest.get(Routes.guildTemplates(guildId)) as Promise<RESTGetAPIGuildTemplatesResult>;
}
/**
* Syncs a template for a guild
*
* @param guildId - The id of the guild to sync the template from
* @param templateCode - The code of the template to sync
*/
public async syncTemplate(guildId: Snowflake, templateCode: string) {
return this.rest.put(Routes.guildTemplate(guildId, templateCode)) as Promise<RESTPutAPIGuildTemplateSyncResult>;
}
/**
* Edits a template for a guild
*
* @param guildId - The id of the guild to edit the template from
* @param templateCode - The code of the template to edit
* @param data - The data for editing the template
*/
public async editTemplate(guildId: Snowflake, templateCode: string, data: RESTPatchAPIGuildTemplateJSONBody) {
return this.rest.patch(Routes.guildTemplate(guildId, templateCode), {
body: data,
}) as Promise<RESTPatchAPIGuildTemplateResult>;
}
/**
* Deletes a template for a guild
*
* @param guildId - The id of the guild to delete the template from
* @param templateCode - The code of the template to delete
*/
public async deleteTemplate(guildId: Snowflake, templateCode: string) {
await this.rest.delete(Routes.guildTemplate(guildId, templateCode));
}
/**
* Fetches all the stickers for a guild
*
* @param guildId - The id of the guild to fetch the stickers from
*/
public async getStickers(guildId: Snowflake) {
return this.rest.get(Routes.guildStickers(guildId)) as Promise<RESTGetAPIGuildStickersResult>;
}
/**
* Fetches a sticker for a guild
*
* @param guildId - The id of the guild to fetch the sticker from
* @param stickerId - The id of the sticker to fetch
*/
public async getSticker(guildId: Snowflake, stickerId: Snowflake) {
return this.rest.get(Routes.guildSticker(guildId, stickerId)) as Promise<RESTGetAPIGuildStickerResult>;
}
/**
* Creates a sticker for a guild
*
* @param guildId - The id of the guild to create the sticker for
* @param data - The data for creating the sticker
* @param reason - The reason for creating the sticker
*/
public async createSticker(
guildId: Snowflake,
{ file, ...body }: Omit<RESTPostAPIGuildStickerFormDataBody, 'file'> & { file: RawFile },
reason?: string,
) {
const fileData = { ...file, key: 'file' };
return this.rest.post(Routes.guildStickers(guildId), {
appendToFormData: true,
body,
files: [fileData],
reason,
}) as Promise<RESTPostAPIGuildStickerResult>;
}
/**
* Edits a sticker for a guild
*
* @param guildId - The id of the guild to edit the sticker from
* @param stickerId - The id of the sticker to edit
* @param data - The data for editing the sticker
* @param reason - The reason for editing the sticker
*/
public async editSticker(
guildId: Snowflake,
stickerId: Snowflake,
data: RESTPatchAPIGuildStickerJSONBody,
reason?: string,
) {
return this.rest.patch(Routes.guildSticker(guildId, stickerId), {
reason,
body: data,
}) as Promise<RESTPatchAPIGuildStickerResult>;
}
/**
* Deletes a sticker for a guild
*
* @param guildId - The id of the guild to delete the sticker from
* @param stickerId - The id of the sticker to delete
* @param reason - The reason for deleting the sticker
*/
public async deleteSticker(guildId: Snowflake, stickerId: Snowflake, reason?: string) {
await this.rest.delete(Routes.guildSticker(guildId, stickerId), { reason });
}
/**
* Fetches the audit logs for a guild
*
* @param guildId - The id of the guild to fetch the audit logs from
* @param options - The options for fetching the audit logs
*/
public async getAuditLogs(guildId: Snowflake, options: RESTGetAPIAuditLogQuery = {}) {
return this.rest.get(Routes.guildAuditLog(guildId), {
query: makeURLSearchParams(options as Record<string, unknown>),
}) as Promise<RESTGetAPIAuditLogResult>;
}
/**
* Fetches all auto moderation rules for a guild
*
* @param guildId - The id of the guild to fetch the auto moderation rules from
*/
public async getAutoModerationRules(guildId: Snowflake) {
return this.rest.get(Routes.guildAutoModerationRules(guildId)) as Promise<RESTGetAPIAutoModerationRulesResult>;
}
/**
* Fetches an auto moderation rule for a guild
*
* @param guildId - The id of the guild to fetch the auto moderation rule from
* @param ruleId - The id of the auto moderation rule to fetch
*/
public async getAutoModerationRule(guildId: Snowflake, ruleId: Snowflake) {
return this.rest.get(
Routes.guildAutoModerationRule(guildId, ruleId),
) as Promise<RESTGetAPIAutoModerationRuleResult>;
}
/**
* Creates a new auto moderation rule for a guild
*
* @param guildId - The id of the guild to create the auto moderation rule from
* @param data - The data for creating the auto moderation rule
*/
public async createAutoModerationRule(
guildId: Snowflake,
data: RESTPostAPIAutoModerationRuleJSONBody,
reason?: string,
) {
return this.rest.post(Routes.guildAutoModerationRules(guildId), {
reason,
body: data,
}) as Promise<RESTPostAPIAutoModerationRuleResult>;
}
/**
* Edits an auto moderation rule for a guild
*
* @param guildId - The id of the guild to edit the auto moderation rule from
* @param ruleId - The id of the auto moderation rule to edit
* @param data - The data for editing the auto moderation rule
* @param reason - The reason for editing the auto moderation rule
*/
public async editAutoModerationRule(
guildId: Snowflake,
ruleId: Snowflake,
data: RESTPatchAPIAutoModerationRuleJSONBody,
reason?: string,
) {
return this.rest.patch(Routes.guildAutoModerationRule(guildId, ruleId), {
reason,
body: data,
}) as Promise<RESTPatchAPIAutoModerationRuleJSONBody>;
}
/**
* Deletes an auto moderation rule for a guild
*
* @param guildId - The id of the guild to delete the auto moderation rule from
* @param ruleId - The id of the auto moderation rule to delete
* @param reason - The reason for deleting the auto moderation rule
*/
public async deleteAutoModerationRule(guildId: Snowflake, ruleId: Snowflake, reason?: string) {
await this.rest.delete(Routes.guildAutoModerationRule(guildId, ruleId), { reason });
}
/**
* Fetches a guild member
*
* @param guildId - The id of the guild
* @param userId - The id of the user
*/
public async getMember(guildId: Snowflake, userId: Snowflake) {
return this.rest.get(Routes.guildMember(guildId, userId)) as Promise<RESTGetAPIGuildMemberResult>;
}
/**
* Searches for guild members
*
* @param guildId - The id of the guild to search in
* @param query - The query to search for
* @param limit - The maximum number of members to return
*/
public async searchForMembers(guildId: Snowflake, options: RESTGetAPIGuildMembersSearchQuery) {
return this.rest.get(Routes.guildMembersSearch(guildId), {
query: makeURLSearchParams(options as unknown as Record<string, unknown>),
}) as Promise<RESTGetAPIGuildMembersSearchResult>;
}
/**
* Edits a guild member
*
* @param guildId - The id of the guild
* @param userId - The id of the user
* @param data - The data to use when editing the guild member
* @param reason - The reason for editing this guild member
*/
public async editMember(
guildId: Snowflake,
userId: Snowflake,
data: RESTPatchAPIGuildMemberJSONBody = {},
reason?: string,
) {
return this.rest.patch(Routes.guildMember(guildId, userId), {
reason,
body: data,
}) as Promise<RESTPatchAPIGuildMemberResult>;
}
/**
* Adds a role to a guild member
*
* @param guildId - The id of the guild
* @param userId - The id of the user
* @param roleId - The id of the role
* @param reason - The reason for adding this role to the guild member
*/
public async addRoleToMember(guildId: Snowflake, userId: Snowflake, roleId: Snowflake, reason?: string) {
await this.rest.put(Routes.guildMemberRole(guildId, userId, roleId), { reason });
}
/**
* Removes a role from a guild member
*
* @param guildId - The id of the guild
* @param userId - The id of the user
* @param roleId - The id of the role
* @param reason - The reason for removing this role from the guild member
*/
public async removeRoleFromMember(guildId: Snowflake, userId: Snowflake, roleId: Snowflake, reason?: string) {
await this.rest.delete(Routes.guildMemberRole(guildId, userId, roleId), { reason });
}
/**
* Fetches a guild template
*
* @param templateCode - The code of the template
*/
public async getTemplate(templateCode: string) {
return this.rest.get(Routes.template(templateCode)) as Promise<RESTGetAPITemplateResult>;
}
/**
* Creates a new template
*
* @param templateCode - The code of the template
* @param data - The data to use when creating the template
*/
public async createTemplate(templateCode: string, data: RESTPostAPITemplateCreateGuildJSONBody) {
return this.rest.post(Routes.template(templateCode), { body: data }) as Promise<RESTPostAPIGuildTemplatesResult>;
}
}

View file

@ -0,0 +1,57 @@
import type { REST } from '@discordjs/rest';
import { ApplicationCommandsAPI } from './applicationCommands.js';
import { ChannelsAPI } from './channel.js';
import { GuildsAPI } from './guild.js';
import { InteractionsAPI } from './interactions.js';
import { InvitesAPI } from './invite.js';
import { StickersAPI } from './sticker.js';
import { ThreadsAPI } from './thread.js';
import { UsersAPI } from './user.js';
import { VoiceAPI } from './voice.js';
import { WebhooksAPI } from './webhook.js';
export * from './applicationCommands.js';
export * from './channel.js';
export * from './guild.js';
export * from './interactions.js';
export * from './invite.js';
export * from './sticker.js';
export * from './thread.js';
export * from './user.js';
export * from './voice.js';
export * from './webhook.js';
export class API {
public readonly applicationCommands: ApplicationCommandsAPI;
public readonly channels: ChannelsAPI;
public readonly guilds: GuildsAPI;
public readonly interactions: InteractionsAPI;
public readonly invites: InvitesAPI;
public readonly stickers: StickersAPI;
public readonly threads: ThreadsAPI;
public readonly users: UsersAPI;
public readonly voice: VoiceAPI;
public readonly webhooks: WebhooksAPI;
public constructor(public readonly rest: REST) {
this.applicationCommands = new ApplicationCommandsAPI(rest);
this.channels = new ChannelsAPI(rest);
this.guilds = new GuildsAPI(rest);
this.invites = new InvitesAPI(rest);
this.stickers = new StickersAPI(rest);
this.threads = new ThreadsAPI(rest);
this.users = new UsersAPI(rest);
this.voice = new VoiceAPI(rest);
this.webhooks = new WebhooksAPI(rest);
this.interactions = new InteractionsAPI(rest, this.webhooks);
}
}

View file

@ -0,0 +1,181 @@
import type { RawFile, REST } from '@discordjs/rest';
import type { Snowflake } from 'discord-api-types/v10';
import {
InteractionResponseType,
Routes,
type APICommandAutocompleteInteractionResponseCallbackData,
type APIInteractionResponseCallbackData,
type APIModalInteractionResponseCallbackData,
type RESTGetAPIWebhookWithTokenMessageResult,
} from 'discord-api-types/v10';
import type { WebhooksAPI } from './webhook.js';
export class InteractionsAPI {
public constructor(private readonly rest: REST, private readonly webhooks: WebhooksAPI) {}
/**
* Replies to an interaction
*
* @param interactionId - The id of the interaction
* @param interactionToken - The token of the interaction
* @param data - The data to use when replying
*/
public async reply(
interactionId: Snowflake,
interactionToken: string,
{ files, ...data }: APIInteractionResponseCallbackData & { files?: RawFile[] },
) {
await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), {
files,
body: {
type: InteractionResponseType.ChannelMessageWithSource,
data,
},
});
}
/**
* Defers the reply to an interaction
*
* @param interactionId - The id of the interaction
* @param interactionToken - The token of the interaction
*/
public async defer(interactionId: Snowflake, interactionToken: string) {
await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), {
body: {
type: InteractionResponseType.DeferredChannelMessageWithSource,
},
});
}
/**
* Defers an update from a message component interaction
*
* @param interactionId - The id of the interaction
* @param interactionToken - The token of the interaction
*/
public async deferMessageUpdate(interactionId: Snowflake, interactionToken: string) {
await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), {
body: {
type: InteractionResponseType.DeferredMessageUpdate,
},
});
}
/**
* Reply to a deferred interaction
*
* @param applicationId - The application id of the interaction
* @param interactionToken - The token of the interaction
* @param data - The data to use when replying
*/
public async followUp(
applicationId: Snowflake,
interactionToken: string,
data: APIInteractionResponseCallbackData & { files?: RawFile[] },
) {
await this.webhooks.execute(applicationId, interactionToken, data);
}
/**
* Edits the initial reply to an interaction
*
* @param applicationId - The application id of the interaction
* @param interactionToken - The token of the interaction
* @param data - The data to use when editing the reply
* @param messageId - The id of the message to edit. If omitted, the original reply will be edited
*/
public async editReply(
applicationId: Snowflake,
interactionToken: string,
data: APIInteractionResponseCallbackData & { files?: RawFile[] },
messageId?: string,
) {
return this.webhooks.editMessage(applicationId, interactionToken, messageId ?? '@original', data);
}
/**
* Fetches the initial reply to an interaction
*
* @param applicationId - The application id of the interaction
* @param interactionToken - The token of the interaction
*/
public async getOriginalReply(applicationId: Snowflake, interactionToken: string) {
return this.webhooks.getMessage(
applicationId,
interactionToken,
'@original',
) as Promise<RESTGetAPIWebhookWithTokenMessageResult>;
}
/**
* Deletes the initial reply to an interaction
*
* @param applicationId - The application id of the interaction
* @param interactionToken - The token of the interaction
*/
public async deleteReply(applicationId: Snowflake, interactionToken: string) {
await this.webhooks.deleteMessage(applicationId, interactionToken, '@original');
}
/**
* Updates the the message the component interaction was triggered on
*
* @param interactionId - The id of the interaction
* @param interactionToken - The token of the interaction
* @param data - The data to use when updating the interaction
*/
public async updateMessage(
interactionId: Snowflake,
interactionToken: string,
{ files, ...data }: APIInteractionResponseCallbackData & { files?: RawFile[] },
) {
await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), {
files,
body: {
type: InteractionResponseType.UpdateMessage,
data,
},
});
}
/**
* Sends an autocomplete response to an interaction
*
* @param interactionId - The id of the interaction
* @param interactionToken - The token of the interaction
* @param data - Data for the autocomplete response
*/
public async createAutocompleteResponse(
interactionId: Snowflake,
interactionToken: string,
data: APICommandAutocompleteInteractionResponseCallbackData,
) {
await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), {
body: {
type: InteractionResponseType.ApplicationCommandAutocompleteResult,
data,
},
});
}
/**
* Sends a modal response to an interaction
*
* @param interactionId - The id of the interaction
* @param interactionToken - The token of the interaction
* @param data - The modal to send
*/
public async createModal(
interactionId: Snowflake,
interactionToken: string,
data: APIModalInteractionResponseCallbackData,
) {
await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), {
body: {
type: InteractionResponseType.Modal,
data,
},
});
}
}

View file

@ -0,0 +1,27 @@
import { makeURLSearchParams, type REST } from '@discordjs/rest';
import { Routes, type RESTGetAPIInviteQuery, type RESTGetAPIInviteResult } from 'discord-api-types/v10';
export class InvitesAPI {
public constructor(private readonly rest: REST) {}
/**
* Fetches an invite
*
* @param code - The invite code
*/
public async get(code: string, options: RESTGetAPIInviteQuery = {}) {
return this.rest.get(Routes.invite(code), {
query: makeURLSearchParams(options as Record<string, unknown>),
}) as Promise<RESTGetAPIInviteResult>;
}
/**
* Deletes an invite
*
* @param code - The invite code
* @param reason - The reason for deleting the invite
*/
public async delete(code: string, reason?: string) {
await this.rest.delete(Routes.invite(code), { reason });
}
}

View file

@ -0,0 +1,27 @@
import type { REST } from '@discordjs/rest';
import {
Routes,
type RESTGetAPIStickerResult,
type RESTGetNitroStickerPacksResult,
type Snowflake,
} from 'discord-api-types/v10';
export class StickersAPI {
public constructor(private readonly rest: REST) {}
/**
* Fetches all of the nitro sticker packs
*/
public async getNitroStickers() {
return this.rest.get(Routes.nitroStickerPacks()) as Promise<RESTGetNitroStickerPacksResult>;
}
/**
* Fetches a sticker
*
* @param stickerId - The id of the sticker
*/
public async get(stickerId: Snowflake) {
return this.rest.get(Routes.sticker(stickerId)) as Promise<RESTGetAPIStickerResult>;
}
}

View file

@ -0,0 +1,117 @@
import type { RawFile, REST } from '@discordjs/rest';
import {
Routes,
type APIThreadChannel,
type APIThreadMember,
type RESTGetAPIChannelThreadMembersResult,
type RESTPostAPIChannelThreadsJSONBody,
type RESTPostAPIChannelThreadsResult,
type RESTPostAPIGuildForumThreadsJSONBody,
type Snowflake,
} from 'discord-api-types/v10';
export interface StartThreadOptions extends RESTPostAPIChannelThreadsJSONBody {
message_id?: string;
}
export interface StartForumThreadOptions extends RESTPostAPIGuildForumThreadsJSONBody {
message: RESTPostAPIGuildForumThreadsJSONBody['message'] & { files?: RawFile[] };
}
export class ThreadsAPI {
public constructor(private readonly rest: REST) {}
/**
* Fetches a thread
*
* @param channelId - The id of the channel to fetch the thread from
* @param threadId - The id of the thread
*/
public async get(channelId: Snowflake, threadId: Snowflake) {
return this.rest.get(Routes.threads(channelId, threadId)) as Promise<APIThreadChannel>;
}
/**
* Creates a new thread
*
* @param channelId - The id of the channel to start the thread in
* @param data - The data to use when starting the thread
*/
public async create(channelId: Snowflake, { message_id, ...body }: StartThreadOptions) {
return this.rest.post(Routes.threads(channelId, message_id), { body }) as Promise<RESTPostAPIChannelThreadsResult>;
}
/**
* Creates a new forum post
*
* @param channelId - The id of the forum channel to start the thread in
* @param data - The data to use when starting the thread
*/
public async createForumThread(channelId: Snowflake, { message, ...optionsBody }: StartForumThreadOptions) {
const { files, ...messageBody } = message;
const body = {
...optionsBody,
message: messageBody,
};
return this.rest.post(Routes.threads(channelId), { files, body }) as Promise<APIThreadChannel>;
}
/**
* Adds the current user to a thread
*
* @param threadId - The id of the thread to join
*/
public async join(threadId: Snowflake) {
await this.rest.put(Routes.threadMembers(threadId, '@me'));
}
/**
* Adds a member to a thread
*
* @param threadId - The id of the thread to add the member to
* @param userId - The id of the user to add to the thread
*/
public async addMember(threadId: Snowflake, userId: Snowflake) {
await this.rest.put(Routes.threadMembers(threadId, userId));
}
/**
* Removes the current user from a thread
*
* @param threadId - The id of the thread to leave
*/
public async leave(threadId: Snowflake) {
await this.rest.delete(Routes.threadMembers(threadId, '@me'));
}
/**
* Removes a member from a thread
*
* @param threadId - The id of the thread to remove the member from
* @param userId - The id of the user to remove from the thread
*/
public async removeMember(threadId: Snowflake, userId: Snowflake) {
await this.rest.delete(Routes.threadMembers(threadId, userId));
}
/**
* Fetches a member of a thread
*
* @param threadId - The id of the thread to fetch the member from
* @param userId - The id of the user
*/
public async getMember(threadId: Snowflake, userId: Snowflake) {
return this.rest.get(Routes.threadMembers(threadId, userId)) as Promise<APIThreadMember>;
}
/**
* Fetches all members of a thread
*
* @param threadId - The id of the thread to fetch the members from
*/
public async getAllMembers(threadId: Snowflake) {
return this.rest.get(Routes.threadMembers(threadId)) as Promise<RESTGetAPIChannelThreadMembersResult>;
}
}

View file

@ -0,0 +1,112 @@
import { makeURLSearchParams, type REST } from '@discordjs/rest';
import {
Routes,
type RESTGetAPICurrentUserGuildsQuery,
type RESTGetAPICurrentUserGuildsResult,
type RESTGetAPICurrentUserResult,
type RESTGetAPIUserResult,
type RESTGetCurrentUserGuildMemberResult,
type RESTPatchAPICurrentUserJSONBody,
type RESTPatchAPICurrentUserResult,
type RESTPatchAPIGuildMemberJSONBody,
type RESTPatchAPIGuildMemberResult,
type RESTPatchAPIGuildVoiceStateCurrentMemberJSONBody,
type RESTPatchAPIGuildVoiceStateCurrentMemberResult,
type RESTPostAPICurrentUserCreateDMChannelResult,
type Snowflake,
} from 'discord-api-types/v10';
export class UsersAPI {
public constructor(private readonly rest: REST) {}
/**
* Fetches a user by their id
*
* @param userId - The id of the user to fetch
*/
public async get(userId: Snowflake) {
return this.rest.get(Routes.user(userId)) as Promise<RESTGetAPIUserResult>;
}
/**
* Returns the user object of the requester's account
*/
public async getCurrent() {
return this.rest.get(Routes.user('@me')) as Promise<RESTGetAPICurrentUserResult>;
}
/**
* Returns a list of partial guild objects the current user is a member of
*
* @param options - The options to use when fetching the current user's guilds
*/
public async getGuilds(options: RESTGetAPICurrentUserGuildsQuery = {}) {
return this.rest.get(Routes.userGuilds(), {
query: makeURLSearchParams(options as Record<string, unknown>),
}) as Promise<RESTGetAPICurrentUserGuildsResult>;
}
/**
* Leaves the guild with the given id
*
* @param guildId - The id of the guild
*/
public async leaveGuild(guildId: Snowflake) {
await this.rest.delete(Routes.userGuild(guildId));
}
/**
* Edits the current user
*
* @param user - The new data for the current user
*/
public async edit(user: RESTPatchAPICurrentUserJSONBody) {
return this.rest.patch(Routes.user('@me'), { body: user }) as Promise<RESTPatchAPICurrentUserResult>;
}
/**
* Fetches the guild member for the current user
*
* @param guildId - The id of the guild
*/
public async getGuildMember(guildId: Snowflake) {
return this.rest.get(Routes.userGuildMember(guildId)) as Promise<RESTGetCurrentUserGuildMemberResult>;
}
/**
* Edits the guild member for the current user
*
* @param guildId - The id of the guild
* @param member - The new data for the guild member
* @param reason - The reason for editing this guild member
*/
public async editGuildMember(guildId: Snowflake, member: RESTPatchAPIGuildMemberJSONBody = {}, reason?: string) {
return this.rest.patch(Routes.guildMember(guildId, '@me'), {
reason,
body: member,
}) as Promise<RESTPatchAPIGuildMemberResult>;
}
/**
* Sets the voice state for the current user
*
* @param guildId - The id of the guild
* @param options - The options to use when setting the voice state
*/
public async setVoiceState(guildId: Snowflake, options: RESTPatchAPIGuildVoiceStateCurrentMemberJSONBody = {}) {
return this.rest.patch(Routes.guildVoiceState(guildId, '@me'), {
body: options,
}) as Promise<RESTPatchAPIGuildVoiceStateCurrentMemberResult>;
}
/**
* Opens a new DM channel with a user
*
* @param userId - The id of the user to open a DM channel with
*/
public async createDM(userId: Snowflake) {
return this.rest.post(Routes.userChannels(), {
body: { recipient_id: userId },
}) as Promise<RESTPostAPICurrentUserCreateDMChannelResult>;
}
}

View file

@ -0,0 +1,13 @@
import type { REST } from '@discordjs/rest';
import { Routes, type GetAPIVoiceRegionsResult } from 'discord-api-types/v10';
export class VoiceAPI {
public constructor(private readonly rest: REST) {}
/**
* Fetches all voice regions
*/
public async getVoiceRegions() {
return this.rest.get(Routes.voiceRegions()) as Promise<GetAPIVoiceRegionsResult>;
}
}

View file

@ -0,0 +1,214 @@
import { makeURLSearchParams, type RawFile, type REST } from '@discordjs/rest';
import {
Routes,
type RESTGetAPIChannelMessageResult,
type RESTGetAPIWebhookResult,
type RESTPatchAPIWebhookJSONBody,
type RESTPatchAPIWebhookResult,
type RESTPatchAPIWebhookWithTokenMessageJSONBody,
type RESTPatchAPIWebhookWithTokenMessageResult,
type RESTPostAPIChannelWebhookJSONBody,
type RESTPostAPIWebhookWithTokenGitHubQuery,
type RESTPostAPIWebhookWithTokenJSONBody,
type RESTPostAPIWebhookWithTokenQuery,
type RESTPostAPIWebhookWithTokenResult,
type RESTPostAPIWebhookWithTokenSlackQuery,
type RESTPostAPIWebhookWithTokenWaitResult,
type Snowflake,
} from 'discord-api-types/v10';
export class WebhooksAPI {
public constructor(private readonly rest: REST) {}
/**
* Fetches a webhook
*
* @param id - The id of the webhook
* @param token - The token of the webhook
*/
public async get(id: Snowflake, token?: string) {
return this.rest.get(Routes.webhook(id, token)) as Promise<RESTGetAPIWebhookResult>;
}
/**
* Creates a new webhook
*
* @param channelId - The id of the channel to create the webhook in
* @param data - The data to use when creating the webhook
* @param reason - The reason for creating the webhook
*/
public async create(channelId: Snowflake, data: RESTPostAPIChannelWebhookJSONBody, reason?: string) {
return this.rest.post(Routes.channelWebhooks(channelId), {
reason,
body: data,
}) as Promise<RESTPostAPIWebhookWithTokenResult>;
}
/**
* Edits a webhook
*
* @param id - The id of the webhook to edit
* @param webhook - The new webhook data
* @param options - The options to use when editing the webhook
*/
public async edit(
id: Snowflake,
webhook: RESTPatchAPIWebhookJSONBody,
{ token, reason }: { reason?: string; token?: string } = {},
) {
return this.rest.patch(Routes.webhook(id, token), { reason, body: webhook }) as Promise<RESTPatchAPIWebhookResult>;
}
/**
* Deletes a webhook
*
* @param id - The id of the webhook to delete
* @param options - The options to use when deleting the webhook
*/
public async delete(id: Snowflake, { token, reason }: { reason?: string; token?: string } = {}) {
await this.rest.delete(Routes.webhook(id, token), { reason });
}
/**
* Executes a webhook and returns the created message
*
* @param id - The id of the webhook
* @param token - The token of the webhook
* @param data - The data to use when executing the webhook
*/
public async execute(
id: Snowflake,
token: string,
data: RESTPostAPIWebhookWithTokenJSONBody & RESTPostAPIWebhookWithTokenQuery & { files?: RawFile[]; wait: true },
): Promise<RESTPostAPIWebhookWithTokenWaitResult>;
/**
* Executes a webhook
*
* @param id - The id of the webhook
* @param token - The token of the webhook
* @param data - The data to use when executing the webhook
*/
public async execute(
id: Snowflake,
token: string,
data: RESTPostAPIWebhookWithTokenJSONBody & RESTPostAPIWebhookWithTokenQuery & { files?: RawFile[]; wait?: false },
): Promise<void>;
/**
* Executes a webhook
*
* @param id - The id of the webhook
* @param token - The token of the webhook
* @param data - The data to use when executing the webhook
*/
public async execute(
id: Snowflake,
token: string,
{
wait,
thread_id,
files,
...body
}: RESTPostAPIWebhookWithTokenJSONBody & RESTPostAPIWebhookWithTokenQuery & { files?: RawFile[] },
) {
return this.rest.post(Routes.webhook(id, token), {
query: makeURLSearchParams({ wait, thread_id }),
files,
body,
auth: false,
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
}) as Promise<RESTPostAPIWebhookWithTokenWaitResult | void>;
}
/**
* Executes a slack webhook
*
* @param id - The id of the webhook
* @param token - The token of the webhook
* @param options - The options to use when executing the webhook
*/
public async executeSlack(
id: Snowflake,
token: string,
body: unknown,
options: RESTPostAPIWebhookWithTokenSlackQuery = {},
) {
await this.rest.post(Routes.webhookPlatform(id, token, 'slack'), {
query: makeURLSearchParams(options as Record<string, unknown>),
body,
auth: false,
});
}
/**
* Executes a github webhook
*
* @param id - The id of the webhook
* @param token - The token of the webhook
* @param options - The options to use when executing the webhook
*/
public async executeGitHub(
id: Snowflake,
token: string,
body: unknown,
options: RESTPostAPIWebhookWithTokenGitHubQuery = {},
) {
await this.rest.post(Routes.webhookPlatform(id, token, 'github'), {
query: makeURLSearchParams(options as Record<string, unknown>),
body,
auth: false,
});
}
/**
* Fetches an associated message from a webhook
*
* @param id - The id of the webhook
* @param token - The token of the webhook
* @param messageId - The id of the message to fetch
* @param options - The options to use when fetching the message
*/
public async getMessage(id: Snowflake, token: string, messageId: Snowflake, options: { thread_id?: string } = {}) {
return this.rest.get(Routes.webhookMessage(id, token, messageId), {
query: makeURLSearchParams(options as Record<string, unknown>),
auth: false,
}) as Promise<RESTGetAPIChannelMessageResult>;
}
/**
* Edits an associated message from a webhook
*
* @param id - The id of the webhook
* @param token - The token of the webhook
* @param messageId - The id of the message to edit
* @param data - The data to use when editing the message
*/
public async editMessage(
id: Snowflake,
token: string,
messageId: Snowflake,
{ thread_id, ...body }: RESTPatchAPIWebhookWithTokenMessageJSONBody & { thread_id?: string },
) {
return this.rest.patch(Routes.webhookMessage(id, token, messageId), {
query: makeURLSearchParams({ thread_id }),
auth: false,
body,
}) as Promise<RESTPatchAPIWebhookWithTokenMessageResult>;
}
/**
* Deletes an associated message from a webhook
*
* @param id - The id of the webhook
* @param token - The token of the webhook
* @param messageId - The id of the message to delete
* @param options - The options to use when deleting the message
*/
public async deleteMessage(id: Snowflake, token: string, messageId: Snowflake, options: { thread_id?: string } = {}) {
await this.rest.delete(Routes.webhookMessage(id, token, messageId), {
query: makeURLSearchParams(options as Record<string, unknown>),
auth: false,
});
}
}

179
packages/core/src/client.ts Normal file
View file

@ -0,0 +1,179 @@
import type { REST } from '@discordjs/rest';
import { WebSocketShardEvents, type WebSocketManager } from '@discordjs/ws';
import { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';
import type {
GatewayAutoModerationActionExecutionDispatchData,
GatewayAutoModerationRuleCreateDispatchData,
GatewayAutoModerationRuleDeleteDispatchData,
GatewayAutoModerationRuleUpdateDispatchData,
GatewayChannelCreateDispatchData,
GatewayChannelDeleteDispatchData,
GatewayChannelPinsUpdateDispatchData,
GatewayChannelUpdateDispatchData,
GatewayDispatchEvents,
GatewayGuildBanAddDispatchData,
GatewayGuildBanRemoveDispatchData,
GatewayGuildCreateDispatchData,
GatewayGuildDeleteDispatchData,
GatewayGuildEmojisUpdateDispatchData,
GatewayGuildIntegrationsUpdateDispatchData,
GatewayGuildMemberAddDispatchData,
GatewayGuildMemberRemoveDispatchData,
GatewayGuildMembersChunkDispatchData,
GatewayGuildMemberUpdateDispatchData,
GatewayGuildRoleCreateDispatchData,
GatewayGuildRoleDeleteDispatchData,
GatewayGuildRoleUpdateDispatchData,
GatewayGuildScheduledEventCreateDispatchData,
GatewayGuildScheduledEventDeleteDispatchData,
GatewayGuildScheduledEventUpdateDispatchData,
GatewayGuildScheduledEventUserAddDispatchData,
GatewayGuildScheduledEventUserRemoveDispatchData,
GatewayGuildStickersUpdateDispatchData,
GatewayGuildUpdateDispatchData,
GatewayIntegrationCreateDispatchData,
GatewayIntegrationDeleteDispatchData,
GatewayIntegrationUpdateDispatchData,
GatewayInteractionCreateDispatchData,
GatewayInviteCreateDispatchData,
GatewayInviteDeleteDispatchData,
GatewayMessageCreateDispatchData,
GatewayMessageDeleteBulkDispatchData,
GatewayMessageDeleteDispatchData,
GatewayMessageReactionAddDispatchData,
GatewayMessageReactionRemoveAllDispatchData,
GatewayMessageReactionRemoveDispatchData,
GatewayMessageReactionRemoveEmojiDispatchData,
GatewayMessageUpdateDispatchData,
GatewayPresenceUpdateDispatchData,
GatewayReadyDispatchData,
GatewayStageInstanceCreateDispatchData,
GatewayStageInstanceDeleteDispatchData,
GatewayStageInstanceUpdateDispatchData,
GatewayThreadCreateDispatchData,
GatewayThreadDeleteDispatchData,
GatewayThreadListSyncDispatchData,
GatewayThreadMembersUpdateDispatchData,
GatewayThreadMemberUpdateDispatchData,
GatewayThreadUpdateDispatchData,
GatewayTypingStartDispatchData,
GatewayUserUpdateDispatchData,
GatewayVoiceServerUpdateDispatchData,
GatewayVoiceStateUpdateDispatchData,
GatewayWebhooksUpdateDispatchData,
} from 'discord-api-types/v10';
import { API } from './api/index.js';
export interface IntrinsicProps {
/**
* The REST API
*/
api: API;
/**
* The id of the shard that emitted the event
*/
shardId: number;
}
export interface WithIntrinsicProps<T> extends IntrinsicProps {
data: T;
}
export interface MappedEvents {
[GatewayDispatchEvents.ChannelCreate]: [WithIntrinsicProps<GatewayChannelCreateDispatchData>];
[GatewayDispatchEvents.ChannelDelete]: [WithIntrinsicProps<GatewayChannelDeleteDispatchData>];
[GatewayDispatchEvents.ChannelPinsUpdate]: [WithIntrinsicProps<GatewayChannelPinsUpdateDispatchData>];
[GatewayDispatchEvents.ChannelUpdate]: [WithIntrinsicProps<GatewayChannelUpdateDispatchData>];
[GatewayDispatchEvents.GuildBanAdd]: [WithIntrinsicProps<GatewayGuildBanAddDispatchData>];
[GatewayDispatchEvents.GuildBanRemove]: [WithIntrinsicProps<GatewayGuildBanRemoveDispatchData>];
[GatewayDispatchEvents.GuildCreate]: [WithIntrinsicProps<GatewayGuildCreateDispatchData>];
[GatewayDispatchEvents.GuildDelete]: [WithIntrinsicProps<GatewayGuildDeleteDispatchData>];
[GatewayDispatchEvents.GuildEmojisUpdate]: [WithIntrinsicProps<GatewayGuildEmojisUpdateDispatchData>];
[GatewayDispatchEvents.GuildIntegrationsUpdate]: [WithIntrinsicProps<GatewayGuildIntegrationsUpdateDispatchData>];
[GatewayDispatchEvents.GuildMemberAdd]: [WithIntrinsicProps<GatewayGuildMemberAddDispatchData>];
[GatewayDispatchEvents.GuildMemberRemove]: [WithIntrinsicProps<GatewayGuildMemberRemoveDispatchData>];
[GatewayDispatchEvents.GuildMemberUpdate]: [WithIntrinsicProps<GatewayGuildMemberUpdateDispatchData>];
[GatewayDispatchEvents.GuildMembersChunk]: [WithIntrinsicProps<GatewayGuildMembersChunkDispatchData>];
[GatewayDispatchEvents.GuildRoleCreate]: [WithIntrinsicProps<GatewayGuildRoleCreateDispatchData>];
[GatewayDispatchEvents.GuildRoleDelete]: [WithIntrinsicProps<GatewayGuildRoleDeleteDispatchData>];
[GatewayDispatchEvents.GuildRoleUpdate]: [WithIntrinsicProps<GatewayGuildRoleUpdateDispatchData>];
[GatewayDispatchEvents.GuildScheduledEventCreate]: [WithIntrinsicProps<GatewayGuildScheduledEventCreateDispatchData>];
[GatewayDispatchEvents.GuildScheduledEventDelete]: [WithIntrinsicProps<GatewayGuildScheduledEventDeleteDispatchData>];
[GatewayDispatchEvents.GuildScheduledEventUpdate]: [WithIntrinsicProps<GatewayGuildScheduledEventUpdateDispatchData>];
[GatewayDispatchEvents.GuildScheduledEventUserAdd]: [
WithIntrinsicProps<GatewayGuildScheduledEventUserAddDispatchData>,
];
[GatewayDispatchEvents.GuildScheduledEventUserRemove]: [
WithIntrinsicProps<GatewayGuildScheduledEventUserRemoveDispatchData>,
];
[GatewayDispatchEvents.GuildStickersUpdate]: [WithIntrinsicProps<GatewayGuildStickersUpdateDispatchData>];
[GatewayDispatchEvents.GuildUpdate]: [WithIntrinsicProps<GatewayGuildUpdateDispatchData>];
[GatewayDispatchEvents.IntegrationCreate]: [WithIntrinsicProps<GatewayIntegrationCreateDispatchData>];
[GatewayDispatchEvents.IntegrationDelete]: [WithIntrinsicProps<GatewayIntegrationDeleteDispatchData>];
[GatewayDispatchEvents.IntegrationUpdate]: [WithIntrinsicProps<GatewayIntegrationUpdateDispatchData>];
[GatewayDispatchEvents.InteractionCreate]: [WithIntrinsicProps<GatewayInteractionCreateDispatchData>];
[GatewayDispatchEvents.InviteCreate]: [WithIntrinsicProps<GatewayInviteCreateDispatchData>];
[GatewayDispatchEvents.InviteDelete]: [WithIntrinsicProps<GatewayInviteDeleteDispatchData>];
[GatewayDispatchEvents.MessageCreate]: [WithIntrinsicProps<GatewayMessageCreateDispatchData>];
[GatewayDispatchEvents.MessageDelete]: [WithIntrinsicProps<GatewayMessageDeleteDispatchData>];
[GatewayDispatchEvents.MessageDeleteBulk]: [WithIntrinsicProps<GatewayMessageDeleteBulkDispatchData>];
[GatewayDispatchEvents.MessageReactionAdd]: [WithIntrinsicProps<GatewayMessageReactionAddDispatchData>];
[GatewayDispatchEvents.MessageReactionRemove]: [WithIntrinsicProps<GatewayMessageReactionRemoveDispatchData>];
[GatewayDispatchEvents.MessageReactionRemoveAll]: [WithIntrinsicProps<GatewayMessageReactionRemoveAllDispatchData>];
[GatewayDispatchEvents.MessageReactionRemoveEmoji]: [
WithIntrinsicProps<GatewayMessageReactionRemoveEmojiDispatchData>,
];
[GatewayDispatchEvents.MessageUpdate]: [WithIntrinsicProps<GatewayMessageUpdateDispatchData>];
[GatewayDispatchEvents.PresenceUpdate]: [WithIntrinsicProps<GatewayPresenceUpdateDispatchData>];
[GatewayDispatchEvents.Ready]: [WithIntrinsicProps<GatewayReadyDispatchData>];
[GatewayDispatchEvents.StageInstanceCreate]: [WithIntrinsicProps<GatewayStageInstanceCreateDispatchData>];
[GatewayDispatchEvents.StageInstanceDelete]: [WithIntrinsicProps<GatewayStageInstanceDeleteDispatchData>];
[GatewayDispatchEvents.StageInstanceUpdate]: [WithIntrinsicProps<GatewayStageInstanceUpdateDispatchData>];
[GatewayDispatchEvents.ThreadCreate]: [WithIntrinsicProps<GatewayThreadCreateDispatchData>];
[GatewayDispatchEvents.ThreadDelete]: [WithIntrinsicProps<GatewayThreadDeleteDispatchData>];
[GatewayDispatchEvents.ThreadListSync]: [WithIntrinsicProps<GatewayThreadListSyncDispatchData>];
[GatewayDispatchEvents.ThreadMemberUpdate]: [WithIntrinsicProps<GatewayThreadMemberUpdateDispatchData>];
[GatewayDispatchEvents.ThreadMembersUpdate]: [WithIntrinsicProps<GatewayThreadMembersUpdateDispatchData>];
[GatewayDispatchEvents.ThreadUpdate]: [WithIntrinsicProps<GatewayThreadUpdateDispatchData>];
[GatewayDispatchEvents.UserUpdate]: [WithIntrinsicProps<GatewayUserUpdateDispatchData>];
[GatewayDispatchEvents.VoiceServerUpdate]: [WithIntrinsicProps<GatewayVoiceServerUpdateDispatchData>];
[GatewayDispatchEvents.VoiceStateUpdate]: [WithIntrinsicProps<GatewayVoiceStateUpdateDispatchData>];
[GatewayDispatchEvents.WebhooksUpdate]: [WithIntrinsicProps<GatewayWebhooksUpdateDispatchData>];
[GatewayDispatchEvents.Resumed]: [WithIntrinsicProps<never>];
[GatewayDispatchEvents.TypingStart]: [WithIntrinsicProps<GatewayTypingStartDispatchData>];
[GatewayDispatchEvents.AutoModerationActionExecution]: [
WithIntrinsicProps<GatewayAutoModerationActionExecutionDispatchData>,
];
[GatewayDispatchEvents.AutoModerationRuleCreate]: [WithIntrinsicProps<GatewayAutoModerationRuleCreateDispatchData>];
[GatewayDispatchEvents.AutoModerationRuleDelete]: [WithIntrinsicProps<GatewayAutoModerationRuleDeleteDispatchData>];
[GatewayDispatchEvents.AutoModerationRuleUpdate]: [WithIntrinsicProps<GatewayAutoModerationRuleUpdateDispatchData>];
}
export type ManagerShardEventsMap = {
[K in keyof MappedEvents]: MappedEvents[K];
};
export interface ClientOptions {
rest: REST;
ws: WebSocketManager;
}
export function createClient({ rest, ws }: ClientOptions) {
const api = new API(rest);
const emitter = new AsyncEventEmitter<ManagerShardEventsMap>();
function wrapIntrinsicProps<T>(obj: T, shardId: number): WithIntrinsicProps<T> {
return {
api,
shardId,
data: obj,
};
}
ws.on(WebSocketShardEvents.Dispatch, ({ data: dispatch, shardId }) => {
// @ts-expect-error event props can't be resolved properly, but they are correct
emitter.emit(dispatch.t, wrapIntrinsicProps(dispatch.d, shardId));
});
return emitter;
}

View file

@ -0,0 +1,5 @@
export * from './api/index.js';
export * from './client.js';
export * from './util/index.js';
export * from 'discord-api-types/v10';

View file

@ -0,0 +1,29 @@
import type { RawFile } from '@discordjs/rest';
import type { APIInteractionResponseCallbackData } from 'discord-api-types/v10';
export interface DescriptiveRawFile extends RawFile {
description?: string;
}
/**
* A utility function to create a form data payload given an array of file buffers
*
* @param files - The files to create a form data payload for
* @param options - The additional options for the form data payload
*/
export function withFiles(files: DescriptiveRawFile[], options: APIInteractionResponseCallbackData) {
const body = {
...options,
attachments: files.map((file, index) => ({
id: index.toString(),
description: file.description,
})),
};
const outputFiles = files.map((file, index) => ({
name: file.name ?? index.toString(),
data: file.data,
}));
return { body, files: outputFiles };
}

View file

@ -0,0 +1 @@
export * from './files.js';

View file

@ -0,0 +1,20 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"allowJs": true
},
"include": [
"**/*.ts",
"**/*.tsx",
"**/*.js",
"**/*.mjs",
"**/*.jsx",
"**/*.test.ts",
"**/*.test.js",
"**/*.test.mjs",
"**/*.spec.ts",
"**/*.spec.js",
"**/*.spec.mjs"
],
"exclude": []
}

View file

@ -0,0 +1,4 @@
{
"extends": "../../tsconfig.json",
"include": ["src/**/*.ts"]
}

View file

@ -0,0 +1,3 @@
import { createTsupConfig } from '../../tsup.config.js';
export default createTsupConfig({});

View file

@ -88,7 +88,7 @@ export interface RequestData {
/**
* Reason to show in the audit logs
*/
reason?: string;
reason?: string | undefined;
/**
* The signal to abort the queue entry or the REST call, where applicable
*/

View file

@ -2089,6 +2089,29 @@ __metadata:
languageName: unknown
linkType: soft
"@discordjs/core@workspace:packages/core":
version: 0.0.0-use.local
resolution: "@discordjs/core@workspace:packages/core"
dependencies:
"@discordjs/rest": "workspace:^"
"@discordjs/ws": "workspace:^"
"@favware/cliff-jumper": ^1.9.0
"@microsoft/api-extractor": ^7.33.6
"@types/node": 16.18.3
"@vitest/coverage-c8": ^0.25.3
"@vladfrangu/async_event_emitter": ^2.1.2
cross-env: ^7.0.3
discord-api-types: ^0.37.20
eslint: ^8.28.0
eslint-config-neon: ^0.1.40
eslint-formatter-pretty: ^4.1.0
prettier: ^2.8.0
tsup: ^6.5.0
typescript: ^4.9.3
vitest: ^0.25.3
languageName: unknown
linkType: soft
"@discordjs/discord.js@workspace:.":
version: 0.0.0-use.local
resolution: "@discordjs/discord.js@workspace:."
@ -2420,7 +2443,7 @@ __metadata:
languageName: unknown
linkType: soft
"@discordjs/ws@workspace:packages/ws":
"@discordjs/ws@workspace:^, @discordjs/ws@workspace:packages/ws":
version: 0.0.0-use.local
resolution: "@discordjs/ws@workspace:packages/ws"
dependencies: