mirror of
https://github.com/discordjs/discord.js.git
synced 2026-05-28 06:20:10 +00:00
Compare commits
112 Commits
@discordjs
...
13.10.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30e89a401d | ||
|
|
03c59e3a83 | ||
|
|
9ce7e5edcf | ||
|
|
2a46d9f58e | ||
|
|
78e494b06e | ||
|
|
ae43bca8b0 | ||
|
|
7321507559 | ||
|
|
d0a4199760 | ||
|
|
96125079a2 | ||
|
|
7b41fb6b5a | ||
|
|
4f7c1e35c3 | ||
|
|
622c77ba7a | ||
|
|
be35db2410 | ||
|
|
e95caa7e45 | ||
|
|
5c1e558570 | ||
|
|
4cf05559a2 | ||
|
|
d9432aba71 | ||
|
|
f2a6f9fc1d | ||
|
|
da3d4873a7 | ||
|
|
64928abb9e | ||
|
|
7b7cc1c6cb | ||
|
|
00a705707e | ||
|
|
4d86cf4ce0 | ||
|
|
beb3d8ec26 | ||
|
|
8fe166dcfd | ||
|
|
9cc336c43b | ||
|
|
a93f4b1ba2 | ||
|
|
f457cdd2de | ||
|
|
f704b261c0 | ||
|
|
631abee693 | ||
|
|
feb8e30d2e | ||
|
|
4063b90cef | ||
|
|
0e0f784447 | ||
|
|
e8d72c7245 | ||
|
|
4ae08ad9ef | ||
|
|
222fc9c679 | ||
|
|
079973f1cf | ||
|
|
125696fc79 | ||
|
|
c198e893c9 | ||
|
|
7e1904c2ad | ||
|
|
c61fc8082a | ||
|
|
65444f510d | ||
|
|
70450f6873 | ||
|
|
3638b4021a | ||
|
|
0ab2227984 | ||
|
|
afb18b99b7 | ||
|
|
613fd43fcf | ||
|
|
3095f350e0 | ||
|
|
0d0190a6fd | ||
|
|
8f6df90035 | ||
|
|
876816ab2a | ||
|
|
a8f2b2cfb4 | ||
|
|
ddfe15b872 | ||
|
|
114bcc07a9 | ||
|
|
76df9fdc45 | ||
|
|
a51420f7f8 | ||
|
|
e3cbd45e7d | ||
|
|
ea28638a0c | ||
|
|
43a7870b23 | ||
|
|
6dcf0bda05 | ||
|
|
816936eafb | ||
|
|
1d09ad4652 | ||
|
|
5165b18b85 | ||
|
|
7afcd9594a | ||
|
|
b9802f4b6f | ||
|
|
1040ce0e71 | ||
|
|
3eb45e30b3 | ||
|
|
ab324ea6ae | ||
|
|
022e138b9a | ||
|
|
9e4a900e6d | ||
|
|
6c5613255a | ||
|
|
ff49b82db7 | ||
|
|
ae7f991e8d | ||
|
|
cedc333940 | ||
|
|
6daee1b235 | ||
|
|
68498a87be | ||
|
|
ab6c2bad84 | ||
|
|
c9e4562fd5 | ||
|
|
e1cdcfa9a6 | ||
|
|
5e8162a137 | ||
|
|
9f09702854 | ||
|
|
8e7d15e49d | ||
|
|
b9c5676006 | ||
|
|
dfea9c27ce | ||
|
|
78140748ce | ||
|
|
a7535a2232 | ||
|
|
7a52785f7d | ||
|
|
13dd82d7fa | ||
|
|
93cdb2f2fa | ||
|
|
611d3a7b2f | ||
|
|
29d42ed319 | ||
|
|
1d97dcff08 | ||
|
|
679b87c4f8 | ||
|
|
b231bece0e | ||
|
|
49397c0ca4 | ||
|
|
215dfe02d5 | ||
|
|
69ba067a65 | ||
|
|
5f621c1995 | ||
|
|
ee1698d928 | ||
|
|
2fcf8af421 | ||
|
|
f0960698d2 | ||
|
|
30baff7ecb | ||
|
|
2b3db734df | ||
|
|
0b54089c43 | ||
|
|
77b8e01911 | ||
|
|
bc5ddc36fa | ||
|
|
5bcca8b97f | ||
|
|
988a51b764 | ||
|
|
1f4e633ce3 | ||
|
|
233084a601 | ||
|
|
ac8c122c2a | ||
|
|
2dabd82e26 |
5
.cliff-jumperrc.json
Normal file
5
.cliff-jumperrc.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "discord.js",
|
||||||
|
"packagePath": ".",
|
||||||
|
"tagTemplate": "{{new-version}}"
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
2,
|
2,
|
||||||
"always",
|
"always",
|
||||||
["chore", "build", "ci", "docs", "feat", "fix", "perf", "refactor", "revert", "style", "test", "types", "typings"]
|
["chore", "build", "ci", "docs", "feat", "fix", "perf", "refactor", "revert", "style", "test", "types", "typings"]
|
||||||
]
|
],
|
||||||
|
"scope-case": [0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
13
.github/check_deploy_branch.sh
vendored
Executable file
13
.github/check_deploy_branch.sh
vendored
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
git diff HEAD^ HEAD --quiet .
|
||||||
|
|
||||||
|
if [[ "$VERCEL_GIT_COMMIT_REF" == "main" && $? -eq 1 ]]; then
|
||||||
|
# Proceed with the build
|
||||||
|
echo "✅ - Proceed"
|
||||||
|
exit 1;
|
||||||
|
else
|
||||||
|
# Don't build
|
||||||
|
echo "🛑 - Build cancelled"
|
||||||
|
exit 0;
|
||||||
|
fi
|
||||||
29
.github/workflows/deploy.yml
vendored
29
.github/workflows/deploy.yml
vendored
@@ -1,29 +0,0 @@
|
|||||||
name: Deployment
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- '*'
|
|
||||||
- '!docs'
|
|
||||||
tags:
|
|
||||||
- '*'
|
|
||||||
jobs:
|
|
||||||
docs:
|
|
||||||
name: Documentation
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Install Node v16
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: 16
|
|
||||||
cache: npm
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm ci
|
|
||||||
|
|
||||||
- name: Build and deploy documentation
|
|
||||||
uses: discordjs/action-docs@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
102
.github/workflows/documentation.yml
vendored
Normal file
102
.github/workflows/documentation.yml
vendored
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
name: Documentation
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'v13'
|
||||||
|
- '!docs'
|
||||||
|
tags:
|
||||||
|
- '**'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
ref:
|
||||||
|
description: 'The branch, tag or SHA to checkout'
|
||||||
|
required: true
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build documentation
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.repository_owner == 'discordjs'
|
||||||
|
outputs:
|
||||||
|
BRANCH_NAME: ${{ steps.env.outputs.BRANCH_NAME }}
|
||||||
|
BRANCH_OR_TAG: ${{ steps.env.outputs.BRANCH_OR_TAG }}
|
||||||
|
SHA: ${{ steps.env.outputs.SHA }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.inputs.ref || '' }}
|
||||||
|
|
||||||
|
- name: Install node.js v16
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 16
|
||||||
|
cache: 'npm'
|
||||||
|
cache-dependency-path: package-lock.json
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Build docs
|
||||||
|
run: npm run docs
|
||||||
|
|
||||||
|
- name: Upload docgen artifacts
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: docgen
|
||||||
|
path: docs/docs.json
|
||||||
|
|
||||||
|
- name: Set outputs for upload job
|
||||||
|
id: env
|
||||||
|
run: |
|
||||||
|
echo "::set-output name=BRANCH_NAME::${GITHUB_REF_NAME}"
|
||||||
|
echo "::set-output name=BRANCH_OR_TAG::${GITHUB_REF_TYPE}"
|
||||||
|
echo "::set-output name=SHA::${GITHUB_SHA}"
|
||||||
|
|
||||||
|
upload:
|
||||||
|
name: Upload Documentation
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
BRANCH_NAME: ${{ github.event.inputs.ref || needs.build.outputs.BRANCH_NAME }}
|
||||||
|
BRANCH_OR_TAG: ${{ needs.build.outputs.BRANCH_OR_TAG }}
|
||||||
|
SHA: ${{ needs.build.outputs.SHA }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install node.js v16
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 16
|
||||||
|
cache: 'npm'
|
||||||
|
cache-dependency-path: package-lock.json
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Download docgen artifacts
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: docgen
|
||||||
|
path: docs
|
||||||
|
|
||||||
|
- name: Checkout docs repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
repository: 'discordjs/docs'
|
||||||
|
token: ${{ secrets.DJS_DOCS }}
|
||||||
|
path: 'out'
|
||||||
|
|
||||||
|
- name: Move docs to correct directory
|
||||||
|
run: |
|
||||||
|
mkdir -p out/discord.js
|
||||||
|
mv docs/docs.json out/discord.js/${BRANCH_NAME}.json
|
||||||
|
|
||||||
|
- name: Commit and push
|
||||||
|
run: |
|
||||||
|
cd out
|
||||||
|
git config user.name github-actions[bot]
|
||||||
|
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
|
||||||
|
git add .
|
||||||
|
git commit -m "Docs build for ${BRANCH_OR_TAG} ${BRANCH_NAME}: ${SHA}" || true
|
||||||
|
git push
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -28,3 +28,4 @@ docs/docs.json
|
|||||||
.tmp/
|
.tmp/
|
||||||
.idea/
|
.idea/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
.yarn/
|
||||||
|
|||||||
2708
CHANGELOG.md
2708
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
77
cliff.toml
77
cliff.toml
@@ -1,33 +1,36 @@
|
|||||||
[changelog]
|
[changelog]
|
||||||
header = """
|
header = """
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.\n
|
All notable changes to this project will be documented in this file.\n
|
||||||
"""
|
"""
|
||||||
body = """
|
body = """
|
||||||
{% if version %}\
|
{% if version %}\
|
||||||
# [{{ version | trim_start_matches(pat="v") }}]\
|
# [{{ version | trim_start_matches(pat="v") }}]\
|
||||||
{% if previous %}\
|
{% if previous %}\
|
||||||
{% if previous.version %}\
|
{% if previous.version %}\
|
||||||
(https://github.com/discordjs/discord.js/compare/{{ previous.version }}...{{ version }})\
|
(https://github.com/discordjs/discord.js/compare/{{ previous.version }}...{{ version }})\
|
||||||
{% else %}
|
{% else %}\
|
||||||
(https://github.com/discordjs/discord.js/tree/{{ version }}\
|
(https://github.com/discordjs/discord.js/tree/{{ version }})\
|
||||||
{% endif %}\
|
{% endif %}\
|
||||||
{% endif %} \
|
{% endif %} \
|
||||||
- ({{ timestamp | date(format="%Y-%m-%d") }})
|
- ({{ timestamp | date(format="%Y-%m-%d") }})
|
||||||
{% else %}\
|
{% else %}\
|
||||||
# [unreleased]
|
# [unreleased]
|
||||||
{% endif %}\
|
{% endif %}\
|
||||||
{% for group, commits in commits | group_by(attribute="group") %}
|
{% for group, commits in commits | group_by(attribute="group") %}
|
||||||
## {{ group | upper_first }}
|
## {{ group | upper_first }}
|
||||||
{% for commit in commits %}
|
{% for commit in commits %}
|
||||||
- {% if commit.breaking %}\
|
- {% if commit.scope %}\
|
||||||
[**breaking**] \
|
**{{commit.scope}}:** \
|
||||||
{% endif %}\
|
{% endif %}\
|
||||||
{% if commit.scope %}\
|
{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}](https://github.com/discordjs/discord.js/commit/{{ commit.id }}))\
|
||||||
**{{commit.scope}}:** \
|
{% if commit.breaking %}\
|
||||||
{% endif %}\
|
{% for breakingChange in commit.footers %}\
|
||||||
{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}](https://github.com/discordjs/discord.js/commit/{{ commit.id }}))\
|
\n{% raw %} {% endraw %}- **{{ breakingChange.token }}{{ breakingChange.separator }}** {{ breakingChange.value }}\
|
||||||
{% endfor %}
|
{% endfor %}\
|
||||||
|
{% endif %}\
|
||||||
|
{% endfor %}
|
||||||
{% endfor %}\n
|
{% endfor %}\n
|
||||||
"""
|
"""
|
||||||
trim = true
|
trim = true
|
||||||
@@ -37,25 +40,25 @@ footer = ""
|
|||||||
conventional_commits = true
|
conventional_commits = true
|
||||||
filter_unconventional = true
|
filter_unconventional = true
|
||||||
commit_parsers = [
|
commit_parsers = [
|
||||||
{ message = "^feat", group = "Features"},
|
{ message = "^feat", group = "Features"},
|
||||||
{ message = "^fix", group = "Bug Fixes"},
|
{ message = "^fix", group = "Bug Fixes"},
|
||||||
{ message = "^docs", group = "Documentation"},
|
{ message = "^docs", group = "Documentation"},
|
||||||
{ message = "^perf", group = "Performance"},
|
{ message = "^perf", group = "Performance"},
|
||||||
{ message = "^refactor", group = "Refactor"},
|
{ message = "^refactor", group = "Refactor"},
|
||||||
{ message = "^typings", group = "Typings"},
|
{ message = "^typings", group = "Typings"},
|
||||||
{ message = "^types", group = "Typings"},
|
{ message = "^types", group = "Typings"},
|
||||||
{ message = ".*deprecated", body = ".*deprecated", group = "Deprecation"},
|
{ message = ".*deprecated", body = ".*deprecated", group = "Deprecation"},
|
||||||
{ message = "^revert", skip = true},
|
{ message = "^revert", skip = true},
|
||||||
{ message = "^style", group = "Styling"},
|
{ message = "^style", group = "Styling"},
|
||||||
{ message = "^test", group = "Testing"},
|
{ message = "^test", group = "Testing"},
|
||||||
{ message = "^chore", skip = true},
|
{ message = "^chore", skip = true},
|
||||||
{ message = "^ci", skip = true},
|
{ message = "^ci", skip = true},
|
||||||
{ message = "^build", skip = true},
|
{ message = "^build", skip = true},
|
||||||
{ body = ".*security", group = "Security"},
|
{ body = ".*security", group = "Security"},
|
||||||
]
|
]
|
||||||
filter_commits = true
|
filter_commits = true
|
||||||
tag_pattern = "[0-9]*"
|
tag_pattern = "[0-9]*"
|
||||||
skip_tags = "v[0-9]*|11|12"
|
skip_tags = "v[0-9]*|11|12|@discordjs"
|
||||||
ignore_tags = ""
|
ignore_tags = ""
|
||||||
topo_order = false
|
date_order = true
|
||||||
sort_commits = "newest"
|
sort_commits = "newest"
|
||||||
|
|||||||
5997
package-lock.json
generated
5997
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
50
package.json
50
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "discord.js",
|
"name": "discord.js",
|
||||||
"version": "14.0.0-dev",
|
"version": "13.10.2",
|
||||||
"description": "A powerful library for interacting with the Discord API",
|
"description": "A powerful library for interacting with the Discord API",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "npm run lint && npm run docs:test && npm run lint:typings && npm run test:typescript",
|
"test": "npm run lint && npm run docs:test && npm run lint:typings && npm run test:typescript",
|
||||||
@@ -13,7 +13,8 @@
|
|||||||
"docs": "docgen --source src --custom docs/index.yml --output docs/docs.json",
|
"docs": "docgen --source src --custom docs/index.yml --output docs/docs.json",
|
||||||
"docs:test": "docgen --source src --custom docs/index.yml",
|
"docs:test": "docgen --source src --custom docs/index.yml",
|
||||||
"prepublishOnly": "npm run test",
|
"prepublishOnly": "npm run test",
|
||||||
"changelog": "git cliff --prepend CHANGELOG.md -l"
|
"changelog": "git cliff --prepend CHANGELOG.md -u",
|
||||||
|
"release": "cliff-jumper"
|
||||||
},
|
},
|
||||||
"main": "./src/index.js",
|
"main": "./src/index.js",
|
||||||
"types": "./typings/index.d.ts",
|
"types": "./typings/index.d.ts",
|
||||||
@@ -50,36 +51,37 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://discord.js.org",
|
"homepage": "https://discord.js.org",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discordjs/builders": "^0.11.0",
|
"@discordjs/builders": "^0.16.0",
|
||||||
"@discordjs/collection": "^0.4.0",
|
"@discordjs/collection": "^0.7.0",
|
||||||
"@sapphire/async-queue": "^1.1.9",
|
"@sapphire/async-queue": "^1.3.2",
|
||||||
"@types/node-fetch": "^2.5.12",
|
"@types/node-fetch": "^2.6.2",
|
||||||
"@types/ws": "^8.2.2",
|
"@types/ws": "^8.5.3",
|
||||||
"discord-api-types": "^0.26.0",
|
"discord-api-types": "^0.33.3",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.7",
|
||||||
"ws": "^8.4.0"
|
"ws": "^8.8.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^16.0.1",
|
"@commitlint/cli": "^17.0.3",
|
||||||
"@commitlint/config-angular": "^16.0.0",
|
"@commitlint/config-angular": "^17.0.3",
|
||||||
"@discordjs/docgen": "^0.11.0",
|
"@discordjs/docgen": "^0.11.1",
|
||||||
|
"@favware/cliff-jumper": "^1.8.5",
|
||||||
"@favware/npm-deprecate": "^1.0.4",
|
"@favware/npm-deprecate": "^1.0.4",
|
||||||
"@types/node": "^16.11.12",
|
"@types/node": "^16.11.45",
|
||||||
"conventional-changelog-cli": "^2.2.2",
|
"conventional-changelog-cli": "^2.2.2",
|
||||||
"dtslint": "^4.2.1",
|
"dtslint": "^4.2.1",
|
||||||
"eslint": "^8.5.0",
|
"eslint": "^8.20.0",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-import": "^2.25.3",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"husky": "^7.0.4",
|
"husky": "^8.0.1",
|
||||||
"is-ci": "^3.0.1",
|
"is-ci": "^3.0.1",
|
||||||
"jest": "^27.4.5",
|
"jest": "^28.1.3",
|
||||||
"lint-staged": "^12.1.4",
|
"lint-staged": "^13.0.3",
|
||||||
"prettier": "^2.5.1",
|
"prettier": "^2.7.1",
|
||||||
"tsd": "^0.19.0",
|
"tsd": "^0.22.0",
|
||||||
"tslint": "^6.1.3",
|
"tslint": "^6.1.3",
|
||||||
"typescript": "^4.5.4"
|
"typescript": "^4.7.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16.6.0",
|
"node": ">=16.6.0",
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class GuildMemberRemoveAction extends Action {
|
|||||||
*/
|
*/
|
||||||
if (shard.status === Status.READY) client.emit(Events.GUILD_MEMBER_REMOVE, member);
|
if (shard.status === Status.READY) client.emit(Events.GUILD_MEMBER_REMOVE, member);
|
||||||
}
|
}
|
||||||
|
guild.presences.cache.delete(data.user.id);
|
||||||
guild.voiceStates.cache.delete(data.user.id);
|
guild.voiceStates.cache.delete(data.user.id);
|
||||||
}
|
}
|
||||||
return { guild, member };
|
return { guild, member };
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const AutocompleteInteraction = require('../../structures/AutocompleteInteractio
|
|||||||
const ButtonInteraction = require('../../structures/ButtonInteraction');
|
const ButtonInteraction = require('../../structures/ButtonInteraction');
|
||||||
const CommandInteraction = require('../../structures/CommandInteraction');
|
const CommandInteraction = require('../../structures/CommandInteraction');
|
||||||
const MessageContextMenuInteraction = require('../../structures/MessageContextMenuInteraction');
|
const MessageContextMenuInteraction = require('../../structures/MessageContextMenuInteraction');
|
||||||
|
const ModalSubmitInteraction = require('../../structures/ModalSubmitInteraction');
|
||||||
const SelectMenuInteraction = require('../../structures/SelectMenuInteraction');
|
const SelectMenuInteraction = require('../../structures/SelectMenuInteraction');
|
||||||
const UserContextMenuInteraction = require('../../structures/UserContextMenuInteraction');
|
const UserContextMenuInteraction = require('../../structures/UserContextMenuInteraction');
|
||||||
const { Events, InteractionTypes, MessageComponentTypes, ApplicationCommandTypes } = require('../../util/Constants');
|
const { Events, InteractionTypes, MessageComponentTypes, ApplicationCommandTypes } = require('../../util/Constants');
|
||||||
@@ -17,9 +18,11 @@ class InteractionCreateAction extends Action {
|
|||||||
const client = this.client;
|
const client = this.client;
|
||||||
|
|
||||||
// Resolve and cache partial channels for Interaction#channel getter
|
// Resolve and cache partial channels for Interaction#channel getter
|
||||||
this.getChannel(data);
|
const channel = this.getChannel(data);
|
||||||
|
|
||||||
|
// Do not emit this for interactions that cache messages that are non-text-based.
|
||||||
let InteractionType;
|
let InteractionType;
|
||||||
|
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
case InteractionTypes.APPLICATION_COMMAND:
|
case InteractionTypes.APPLICATION_COMMAND:
|
||||||
switch (data.data.type) {
|
switch (data.data.type) {
|
||||||
@@ -30,6 +33,7 @@ class InteractionCreateAction extends Action {
|
|||||||
InteractionType = UserContextMenuInteraction;
|
InteractionType = UserContextMenuInteraction;
|
||||||
break;
|
break;
|
||||||
case ApplicationCommandTypes.MESSAGE:
|
case ApplicationCommandTypes.MESSAGE:
|
||||||
|
if (channel && !channel.isText()) return;
|
||||||
InteractionType = MessageContextMenuInteraction;
|
InteractionType = MessageContextMenuInteraction;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -41,6 +45,8 @@ class InteractionCreateAction extends Action {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case InteractionTypes.MESSAGE_COMPONENT:
|
case InteractionTypes.MESSAGE_COMPONENT:
|
||||||
|
if (channel && !channel.isText()) return;
|
||||||
|
|
||||||
switch (data.data.component_type) {
|
switch (data.data.component_type) {
|
||||||
case MessageComponentTypes.BUTTON:
|
case MessageComponentTypes.BUTTON:
|
||||||
InteractionType = ButtonInteraction;
|
InteractionType = ButtonInteraction;
|
||||||
@@ -59,6 +65,9 @@ class InteractionCreateAction extends Action {
|
|||||||
case InteractionTypes.APPLICATION_COMMAND_AUTOCOMPLETE:
|
case InteractionTypes.APPLICATION_COMMAND_AUTOCOMPLETE:
|
||||||
InteractionType = AutocompleteInteraction;
|
InteractionType = AutocompleteInteraction;
|
||||||
break;
|
break;
|
||||||
|
case InteractionTypes.MODAL_SUBMIT:
|
||||||
|
InteractionType = ModalSubmitInteraction;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
client.emit(Events.DEBUG, `[INTERACTION] Received interaction with unknown type: ${data.type}`);
|
client.emit(Events.DEBUG, `[INTERACTION] Received interaction with unknown type: ${data.type}`);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ class ThreadCreateAction extends Action {
|
|||||||
* Emitted whenever a thread is created or when the client user is added to a thread.
|
* Emitted whenever a thread is created or when the client user is added to a thread.
|
||||||
* @event Client#threadCreate
|
* @event Client#threadCreate
|
||||||
* @param {ThreadChannel} thread The thread that was created
|
* @param {ThreadChannel} thread The thread that was created
|
||||||
|
* @param {boolean} newlyCreated Whether the thread was newly created
|
||||||
*/
|
*/
|
||||||
client.emit(Events.THREAD_CREATE, thread);
|
client.emit(Events.THREAD_CREATE, thread, data.newly_created ?? false);
|
||||||
}
|
}
|
||||||
return { thread };
|
return { thread };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class WebhooksUpdate extends Action {
|
|||||||
/**
|
/**
|
||||||
* Emitted whenever a channel has its webhooks changed.
|
* Emitted whenever a channel has its webhooks changed.
|
||||||
* @event Client#webhookUpdate
|
* @event Client#webhookUpdate
|
||||||
* @param {TextChannel|NewsChannel} channel The channel that had a webhook update
|
* @param {TextChannel|NewsChannel|VoiceChannel} channel The channel that had a webhook update
|
||||||
*/
|
*/
|
||||||
if (channel) client.emit(Events.WEBHOOKS_UPDATE, channel);
|
if (channel) client.emit(Events.WEBHOOKS_UPDATE, channel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const BeforeReadyWhitelist = [
|
|||||||
WSEvents.GUILD_MEMBER_REMOVE,
|
WSEvents.GUILD_MEMBER_REMOVE,
|
||||||
];
|
];
|
||||||
|
|
||||||
const UNRECOVERABLE_CLOSE_CODES = Object.keys(WSCodes).slice(1).map(Number);
|
const UNRECOVERABLE_CLOSE_CODES = Object.keys(WSCodes).slice(2).map(Number);
|
||||||
const UNRESUMABLE_CLOSE_CODES = [
|
const UNRESUMABLE_CLOSE_CODES = [
|
||||||
RPCErrorCodes.UnknownError,
|
RPCErrorCodes.UnknownError,
|
||||||
RPCErrorCodes.InvalidPermissions,
|
RPCErrorCodes.InvalidPermissions,
|
||||||
@@ -216,13 +216,8 @@ class WebSocketManager extends EventEmitter {
|
|||||||
|
|
||||||
this.shardQueue.add(shard);
|
this.shardQueue.add(shard);
|
||||||
|
|
||||||
if (shard.sessionId) {
|
if (shard.sessionId) this.debug(`Session id is present, attempting an immediate reconnect...`, shard);
|
||||||
this.debug(`Session id is present, attempting an immediate reconnect...`, shard);
|
this.reconnect();
|
||||||
this.reconnect();
|
|
||||||
} else {
|
|
||||||
shard.destroy({ reset: true, emit: false, log: false });
|
|
||||||
this.reconnect();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
shard.on(ShardEvents.INVALID_SESSION, () => {
|
shard.on(ShardEvents.INVALID_SESSION, () => {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const EventEmitter = require('node:events');
|
const EventEmitter = require('node:events');
|
||||||
const { setTimeout, setInterval } = require('node:timers');
|
const { setTimeout, setInterval, clearTimeout } = require('node:timers');
|
||||||
const WebSocket = require('../../WebSocket');
|
const WebSocket = require('../../WebSocket');
|
||||||
const { Status, Events, ShardEvents, Opcodes, WSEvents } = require('../../util/Constants');
|
const { Status, Events, ShardEvents, Opcodes, WSEvents, WSCodes } = require('../../util/Constants');
|
||||||
const Intents = require('../../util/Intents');
|
const Intents = require('../../util/Intents');
|
||||||
|
|
||||||
const STATUS_KEYS = Object.keys(Status);
|
const STATUS_KEYS = Object.keys(Status);
|
||||||
@@ -81,6 +81,13 @@ class WebSocketShard extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
this.lastHeartbeatAcked = true;
|
this.lastHeartbeatAcked = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to prevent calling {@link WebSocketShard#event:close} twice while closing or terminating the WebSocket.
|
||||||
|
* @type {boolean}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this.closeEmitted = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains the rate limit queue and metadata
|
* Contains the rate limit queue and metadata
|
||||||
* @name WebSocketShard#ratelimit
|
* @name WebSocketShard#ratelimit
|
||||||
@@ -126,6 +133,14 @@ class WebSocketShard extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
Object.defineProperty(this, 'helloTimeout', { value: null, writable: true });
|
Object.defineProperty(this, 'helloTimeout', { value: null, writable: true });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The WebSocket timeout.
|
||||||
|
* @name WebSocketShard#wsCloseTimeout
|
||||||
|
* @type {?NodeJS.Timeout}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
Object.defineProperty(this, 'wsCloseTimeout', { value: null, writable: true });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the manager attached its event handlers on the shard
|
* If the manager attached its event handlers on the shard
|
||||||
* @name WebSocketShard#eventsAttached
|
* @name WebSocketShard#eventsAttached
|
||||||
@@ -250,10 +265,11 @@ class WebSocketShard extends EventEmitter {
|
|||||||
|
|
||||||
this.status = this.status === Status.DISCONNECTED ? Status.RECONNECTING : Status.CONNECTING;
|
this.status = this.status === Status.DISCONNECTED ? Status.RECONNECTING : Status.CONNECTING;
|
||||||
this.setHelloTimeout();
|
this.setHelloTimeout();
|
||||||
|
this.setWsCloseTimeout(-1);
|
||||||
this.connectedAt = Date.now();
|
this.connectedAt = Date.now();
|
||||||
|
|
||||||
const ws = (this.connection = WebSocket.create(gateway, wsQuery));
|
// Adding a handshake timeout to just make sure no zombie connection appears.
|
||||||
|
const ws = (this.connection = WebSocket.create(gateway, wsQuery, { handshakeTimeout: 30_000 }));
|
||||||
ws.onopen = this.onOpen.bind(this);
|
ws.onopen = this.onOpen.bind(this);
|
||||||
ws.onmessage = this.onMessage.bind(this);
|
ws.onmessage = this.onMessage.bind(this);
|
||||||
ws.onerror = this.onError.bind(this);
|
ws.onerror = this.onError.bind(this);
|
||||||
@@ -340,21 +356,39 @@ class WebSocketShard extends EventEmitter {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
onClose(event) {
|
onClose(event) {
|
||||||
|
this.closeEmitted = true;
|
||||||
if (this.sequence !== -1) this.closeSequence = this.sequence;
|
if (this.sequence !== -1) this.closeSequence = this.sequence;
|
||||||
this.sequence = -1;
|
this.sequence = -1;
|
||||||
|
this.setHeartbeatTimer(-1);
|
||||||
|
this.setHelloTimeout(-1);
|
||||||
|
// Clearing the WebSocket close timeout as close was emitted.
|
||||||
|
this.setWsCloseTimeout(-1);
|
||||||
|
// If we still have a connection object, clean up its listeners
|
||||||
|
if (this.connection) {
|
||||||
|
this._cleanupConnection();
|
||||||
|
// Having this after _cleanupConnection to just clean up the connection and not listen to ws.onclose
|
||||||
|
this.destroy({ reset: !this.sessionId, emit: false, log: false });
|
||||||
|
}
|
||||||
|
this.status = Status.DISCONNECTED;
|
||||||
|
this.emitClose(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is responsible to emit close event for this shard.
|
||||||
|
* This method helps the shard reconnect.
|
||||||
|
* @param {CloseEvent} [event] Close event that was received
|
||||||
|
*/
|
||||||
|
emitClose(
|
||||||
|
event = {
|
||||||
|
code: 1011,
|
||||||
|
reason: WSCodes[1011],
|
||||||
|
wasClean: false,
|
||||||
|
},
|
||||||
|
) {
|
||||||
this.debug(`[CLOSE]
|
this.debug(`[CLOSE]
|
||||||
Event Code: ${event.code}
|
Event Code: ${event.code}
|
||||||
Clean : ${event.wasClean}
|
Clean : ${event.wasClean}
|
||||||
Reason : ${event.reason ?? 'No reason received'}`);
|
Reason : ${event.reason ?? 'No reason received'}`);
|
||||||
|
|
||||||
this.setHeartbeatTimer(-1);
|
|
||||||
this.setHelloTimeout(-1);
|
|
||||||
// If we still have a connection object, clean up its listeners
|
|
||||||
if (this.connection) this._cleanupConnection();
|
|
||||||
|
|
||||||
this.status = Status.DISCONNECTED;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emitted when a shard's WebSocket closes.
|
* Emitted when a shard's WebSocket closes.
|
||||||
* @private
|
* @private
|
||||||
@@ -432,6 +466,10 @@ class WebSocketShard extends EventEmitter {
|
|||||||
// Set the status to reconnecting
|
// Set the status to reconnecting
|
||||||
this.status = Status.RECONNECTING;
|
this.status = Status.RECONNECTING;
|
||||||
// Finally, emit the INVALID_SESSION event
|
// Finally, emit the INVALID_SESSION event
|
||||||
|
/**
|
||||||
|
* Emitted when the session has been invalidated.
|
||||||
|
* @event WebSocketShard#invalidSession
|
||||||
|
*/
|
||||||
this.emit(ShardEvents.INVALID_SESSION);
|
this.emit(ShardEvents.INVALID_SESSION);
|
||||||
break;
|
break;
|
||||||
case Opcodes.HEARTBEAT_ACK:
|
case Opcodes.HEARTBEAT_ACK:
|
||||||
@@ -523,6 +561,47 @@ class WebSocketShard extends EventEmitter {
|
|||||||
}, 20_000).unref();
|
}, 20_000).unref();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the WebSocket Close timeout.
|
||||||
|
* This method is responsible for detecting any zombie connections if the WebSocket fails to close properly.
|
||||||
|
* @param {number} [time] If set to -1, it will clear the timeout
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
setWsCloseTimeout(time) {
|
||||||
|
if (this.wsCloseTimeout) {
|
||||||
|
this.debug('[WebSocket] Clearing the close timeout.');
|
||||||
|
clearTimeout(this.wsCloseTimeout);
|
||||||
|
}
|
||||||
|
if (time === -1) {
|
||||||
|
this.wsCloseTimeout = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.wsCloseTimeout = setTimeout(() => {
|
||||||
|
this.setWsCloseTimeout(-1);
|
||||||
|
this.debug(`[WebSocket] Close Emitted: ${this.closeEmitted}`);
|
||||||
|
// Check if close event was emitted.
|
||||||
|
if (this.closeEmitted) {
|
||||||
|
this.debug(
|
||||||
|
`[WebSocket] was closed. | WS State: ${
|
||||||
|
CONNECTION_STATE[this.connection?.readyState ?? WebSocket.CLOSED]
|
||||||
|
} | Close Emitted: ${this.closeEmitted}`,
|
||||||
|
);
|
||||||
|
// Setting the variable false to check for zombie connections.
|
||||||
|
this.closeEmitted = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.debug(
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
`[WebSocket] did not close properly, assuming a zombie connection.\nEmitting close and reconnecting again.`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.emitClose();
|
||||||
|
// Setting the variable false to check for zombie connections.
|
||||||
|
this.closeEmitted = false;
|
||||||
|
}, time).unref();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the heartbeat timer for this shard.
|
* Sets the heartbeat timer for this shard.
|
||||||
* @param {number} time If -1, clears the interval, any other number sets an interval
|
* @param {number} time If -1, clears the interval, any other number sets an interval
|
||||||
@@ -563,8 +642,7 @@ class WebSocketShard extends EventEmitter {
|
|||||||
Sequence : ${this.sequence}
|
Sequence : ${this.sequence}
|
||||||
Connection State: ${this.connection ? CONNECTION_STATE[this.connection.readyState] : 'No Connection??'}`,
|
Connection State: ${this.connection ? CONNECTION_STATE[this.connection.readyState] : 'No Connection??'}`,
|
||||||
);
|
);
|
||||||
|
this.destroy({ reset: true, closeCode: 4009 });
|
||||||
this.destroy({ closeCode: 4009, reset: true });
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -713,21 +791,30 @@ class WebSocketShard extends EventEmitter {
|
|||||||
this.setHeartbeatTimer(-1);
|
this.setHeartbeatTimer(-1);
|
||||||
this.setHelloTimeout(-1);
|
this.setHelloTimeout(-1);
|
||||||
|
|
||||||
|
this.debug(
|
||||||
|
`[WebSocket] Destroy: Attempting to close the WebSocket. | WS State: ${
|
||||||
|
CONNECTION_STATE[this.connection?.readyState ?? WebSocket.CLOSED]
|
||||||
|
}`,
|
||||||
|
);
|
||||||
// Step 1: Close the WebSocket connection, if any, otherwise, emit DESTROYED
|
// Step 1: Close the WebSocket connection, if any, otherwise, emit DESTROYED
|
||||||
if (this.connection) {
|
if (this.connection) {
|
||||||
// If the connection is currently opened, we will (hopefully) receive close
|
// If the connection is currently opened, we will (hopefully) receive close
|
||||||
if (this.connection.readyState === WebSocket.OPEN) {
|
if (this.connection.readyState === WebSocket.OPEN) {
|
||||||
this.connection.close(closeCode);
|
this.connection.close(closeCode);
|
||||||
|
this.debug(`[WebSocket] Close: Tried closing. | WS State: ${CONNECTION_STATE[this.connection.readyState]}`);
|
||||||
} else {
|
} else {
|
||||||
// Connection is not OPEN
|
// Connection is not OPEN
|
||||||
this.debug(`WS State: ${CONNECTION_STATE[this.connection.readyState]}`);
|
this.debug(`WS State: ${CONNECTION_STATE[this.connection.readyState]}`);
|
||||||
// Remove listeners from the connection
|
|
||||||
this._cleanupConnection();
|
|
||||||
// Attempt to close the connection just in case
|
// Attempt to close the connection just in case
|
||||||
try {
|
try {
|
||||||
this.connection.close(closeCode);
|
this.connection.close(closeCode);
|
||||||
} catch {
|
} catch (err) {
|
||||||
// No-op
|
this.debug(
|
||||||
|
`[WebSocket] Close: Something went wrong while closing the WebSocket: ${
|
||||||
|
err.message || err
|
||||||
|
}. Forcefully terminating the connection | WS State: ${CONNECTION_STATE[this.connection.readyState]}`,
|
||||||
|
);
|
||||||
|
this.connection.terminate();
|
||||||
}
|
}
|
||||||
// Emit the destroyed event if needed
|
// Emit the destroyed event if needed
|
||||||
if (emit) this._emitDestroyed();
|
if (emit) this._emitDestroyed();
|
||||||
@@ -737,6 +824,15 @@ class WebSocketShard extends EventEmitter {
|
|||||||
this._emitDestroyed();
|
this._emitDestroyed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.connection?.readyState === WebSocket.CLOSING || this.connection?.readyState === WebSocket.CLOSED) {
|
||||||
|
this.closeEmitted = false;
|
||||||
|
this.debug(
|
||||||
|
`[WebSocket] Adding a WebSocket close timeout to ensure a correct WS reconnect.
|
||||||
|
Timeout: ${this.manager.client.options.closeTimeout}ms`,
|
||||||
|
);
|
||||||
|
this.setWsCloseTimeout(this.manager.client.options.closeTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
// Step 2: Null the connection object
|
// Step 2: Null the connection object
|
||||||
this.connection = null;
|
this.connection = null;
|
||||||
|
|
||||||
@@ -766,7 +862,8 @@ class WebSocketShard extends EventEmitter {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_cleanupConnection() {
|
_cleanupConnection() {
|
||||||
this.connection.onopen = this.connection.onclose = this.connection.onerror = this.connection.onmessage = null;
|
this.connection.onopen = this.connection.onclose = this.connection.onmessage = null;
|
||||||
|
this.connection.onerror = () => null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -58,6 +58,14 @@ const Messages = {
|
|||||||
SELECT_OPTION_VALUE: 'MessageSelectOption value must be a string',
|
SELECT_OPTION_VALUE: 'MessageSelectOption value must be a string',
|
||||||
SELECT_OPTION_DESCRIPTION: 'MessageSelectOption description must be a string',
|
SELECT_OPTION_DESCRIPTION: 'MessageSelectOption description must be a string',
|
||||||
|
|
||||||
|
TEXT_INPUT_CUSTOM_ID: 'TextInputComponent customId must be a string',
|
||||||
|
TEXT_INPUT_LABEL: 'TextInputComponent label must be a string',
|
||||||
|
TEXT_INPUT_PLACEHOLDER: 'TextInputComponent placeholder must be a string',
|
||||||
|
TEXT_INPUT_VALUE: 'TextInputComponent value must be a string',
|
||||||
|
|
||||||
|
MODAL_CUSTOM_ID: 'Modal customId must be a string',
|
||||||
|
MODAL_TITLE: 'Modal title must be a string',
|
||||||
|
|
||||||
INTERACTION_COLLECTOR_ERROR: reason => `Collector received no interactions before ending with reason: ${reason}`,
|
INTERACTION_COLLECTOR_ERROR: reason => `Collector received no interactions before ending with reason: ${reason}`,
|
||||||
|
|
||||||
FILE_NOT_FOUND: file => `File could not be found: ${file}`,
|
FILE_NOT_FOUND: file => `File could not be found: ${file}`,
|
||||||
@@ -148,6 +156,10 @@ const Messages = {
|
|||||||
COMMAND_INTERACTION_OPTION_NO_SUB_COMMAND_GROUP: 'No subcommand group specified for interaction.',
|
COMMAND_INTERACTION_OPTION_NO_SUB_COMMAND_GROUP: 'No subcommand group specified for interaction.',
|
||||||
AUTOCOMPLETE_INTERACTION_OPTION_NO_FOCUSED_OPTION: 'No focused option for autocomplete interaction.',
|
AUTOCOMPLETE_INTERACTION_OPTION_NO_FOCUSED_OPTION: 'No focused option for autocomplete interaction.',
|
||||||
|
|
||||||
|
MODAL_SUBMIT_INTERACTION_FIELD_NOT_FOUND: customId => `Required field with custom id "${customId}" not found.`,
|
||||||
|
MODAL_SUBMIT_INTERACTION_FIELD_TYPE: (customId, type, expected) =>
|
||||||
|
`Field with custom id "${customId}" is of type: ${type}; expected ${expected}.`,
|
||||||
|
|
||||||
INVITE_MISSING_SCOPES: 'At least one valid scope must be provided for the invite',
|
INVITE_MISSING_SCOPES: 'At least one valid scope must be provided for the invite',
|
||||||
|
|
||||||
NOT_IMPLEMENTED: (what, name) => `Method ${what} not implemented on ${name}.`,
|
NOT_IMPLEMENTED: (what, name) => `Method ${what} not implemented on ${name}.`,
|
||||||
|
|||||||
@@ -122,6 +122,8 @@ exports.MessageMentions = require('./structures/MessageMentions');
|
|||||||
exports.MessagePayload = require('./structures/MessagePayload');
|
exports.MessagePayload = require('./structures/MessagePayload');
|
||||||
exports.MessageReaction = require('./structures/MessageReaction');
|
exports.MessageReaction = require('./structures/MessageReaction');
|
||||||
exports.MessageSelectMenu = require('./structures/MessageSelectMenu');
|
exports.MessageSelectMenu = require('./structures/MessageSelectMenu');
|
||||||
|
exports.Modal = require('./structures/Modal');
|
||||||
|
exports.ModalSubmitInteraction = require('./structures/ModalSubmitInteraction');
|
||||||
exports.NewsChannel = require('./structures/NewsChannel');
|
exports.NewsChannel = require('./structures/NewsChannel');
|
||||||
exports.OAuth2Guild = require('./structures/OAuth2Guild');
|
exports.OAuth2Guild = require('./structures/OAuth2Guild');
|
||||||
exports.PartialGroupDMChannel = require('./structures/PartialGroupDMChannel');
|
exports.PartialGroupDMChannel = require('./structures/PartialGroupDMChannel');
|
||||||
@@ -140,6 +142,7 @@ exports.StoreChannel = require('./structures/StoreChannel');
|
|||||||
exports.Team = require('./structures/Team');
|
exports.Team = require('./structures/Team');
|
||||||
exports.TeamMember = require('./structures/TeamMember');
|
exports.TeamMember = require('./structures/TeamMember');
|
||||||
exports.TextChannel = require('./structures/TextChannel');
|
exports.TextChannel = require('./structures/TextChannel');
|
||||||
|
exports.TextInputComponent = require('./structures/TextInputComponent');
|
||||||
exports.ThreadChannel = require('./structures/ThreadChannel');
|
exports.ThreadChannel = require('./structures/ThreadChannel');
|
||||||
exports.ThreadMember = require('./structures/ThreadMember');
|
exports.ThreadMember = require('./structures/ThreadMember');
|
||||||
exports.Typing = require('./structures/Typing');
|
exports.Typing = require('./structures/Typing');
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const { isJSONEncodable } = require('@discordjs/builders');
|
||||||
const { Collection } = require('@discordjs/collection');
|
const { Collection } = require('@discordjs/collection');
|
||||||
const ApplicationCommandPermissionsManager = require('./ApplicationCommandPermissionsManager');
|
const ApplicationCommandPermissionsManager = require('./ApplicationCommandPermissionsManager');
|
||||||
const CachedManager = require('./CachedManager');
|
const CachedManager = require('./CachedManager');
|
||||||
const { TypeError } = require('../errors');
|
const { TypeError } = require('../errors');
|
||||||
const ApplicationCommand = require('../structures/ApplicationCommand');
|
const ApplicationCommand = require('../structures/ApplicationCommand');
|
||||||
const { ApplicationCommandTypes } = require('../util/Constants');
|
const { ApplicationCommandTypes } = require('../util/Constants');
|
||||||
|
const Permissions = require('../util/Permissions');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages API methods for application commands and stores their cache.
|
* Manages API methods for application commands and stores their cache.
|
||||||
@@ -53,6 +55,13 @@ class ApplicationCommandManager extends CachedManager {
|
|||||||
* @typedef {ApplicationCommand|Snowflake} ApplicationCommandResolvable
|
* @typedef {ApplicationCommand|Snowflake} ApplicationCommandResolvable
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable max-len */
|
||||||
|
/**
|
||||||
|
* Data that resolves to the data of an ApplicationCommand
|
||||||
|
* @typedef {ApplicationCommandData|APIApplicationCommand|SlashCommandBuilder|ContextMenuCommandBuilder} ApplicationCommandDataResolvable
|
||||||
|
*/
|
||||||
|
/* eslint-enable max-len */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options used to fetch data from Discord
|
* Options used to fetch data from Discord
|
||||||
* @typedef {Object} BaseFetchOptions
|
* @typedef {Object} BaseFetchOptions
|
||||||
@@ -64,6 +73,8 @@ class ApplicationCommandManager extends CachedManager {
|
|||||||
* Options used to fetch Application Commands from Discord
|
* Options used to fetch Application Commands from Discord
|
||||||
* @typedef {BaseFetchOptions} FetchApplicationCommandOptions
|
* @typedef {BaseFetchOptions} FetchApplicationCommandOptions
|
||||||
* @property {Snowflake} [guildId] The guild's id to fetch commands for, for when the guild is not cached
|
* @property {Snowflake} [guildId] The guild's id to fetch commands for, for when the guild is not cached
|
||||||
|
* @property {LocaleString} [locale] The locale to use when fetching this command
|
||||||
|
* @property {boolean} [withLocalizations] Whether to fetch all localization data
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,9 +93,9 @@ class ApplicationCommandManager extends CachedManager {
|
|||||||
* .then(commands => console.log(`Fetched ${commands.size} commands`))
|
* .then(commands => console.log(`Fetched ${commands.size} commands`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
async fetch(id, { guildId, cache = true, force = false } = {}) {
|
async fetch(id, { guildId, cache = true, force = false, locale, withLocalizations } = {}) {
|
||||||
if (typeof id === 'object') {
|
if (typeof id === 'object') {
|
||||||
({ guildId, cache = true } = id);
|
({ guildId, cache = true, locale, withLocalizations } = id);
|
||||||
} else if (id) {
|
} else if (id) {
|
||||||
if (!force) {
|
if (!force) {
|
||||||
const existing = this.cache.get(id);
|
const existing = this.cache.get(id);
|
||||||
@@ -94,13 +105,18 @@ class ApplicationCommandManager extends CachedManager {
|
|||||||
return this._add(command, cache);
|
return this._add(command, cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await this.commandPath({ guildId }).get();
|
const data = await this.commandPath({ guildId }).get({
|
||||||
|
headers: {
|
||||||
|
'X-Discord-Locale': locale,
|
||||||
|
},
|
||||||
|
query: typeof withLocalizations === 'boolean' ? { with_localizations: withLocalizations } : undefined,
|
||||||
|
});
|
||||||
return data.reduce((coll, command) => coll.set(command.id, this._add(command, cache, guildId)), new Collection());
|
return data.reduce((coll, command) => coll.set(command.id, this._add(command, cache, guildId)), new Collection());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an application command.
|
* Creates an application command.
|
||||||
* @param {ApplicationCommandData|APIApplicationCommand} command The command
|
* @param {ApplicationCommandDataResolvable} command The command
|
||||||
* @param {Snowflake} [guildId] The guild's id to create this command in,
|
* @param {Snowflake} [guildId] The guild's id to create this command in,
|
||||||
* ignored when using a {@link GuildApplicationCommandManager}
|
* ignored when using a {@link GuildApplicationCommandManager}
|
||||||
* @returns {Promise<ApplicationCommand>}
|
* @returns {Promise<ApplicationCommand>}
|
||||||
@@ -122,7 +138,7 @@ class ApplicationCommandManager extends CachedManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets all the commands for this application or guild.
|
* Sets all the commands for this application or guild.
|
||||||
* @param {ApplicationCommandData[]|APIApplicationCommand[]} commands The commands
|
* @param {ApplicationCommandDataResolvable[]} commands The commands
|
||||||
* @param {Snowflake} [guildId] The guild's id to create the commands in,
|
* @param {Snowflake} [guildId] The guild's id to create the commands in,
|
||||||
* ignored when using a {@link GuildApplicationCommandManager}
|
* ignored when using a {@link GuildApplicationCommandManager}
|
||||||
* @returns {Promise<Collection<Snowflake, ApplicationCommand>>}
|
* @returns {Promise<Collection<Snowflake, ApplicationCommand>>}
|
||||||
@@ -152,7 +168,7 @@ class ApplicationCommandManager extends CachedManager {
|
|||||||
/**
|
/**
|
||||||
* Edits an application command.
|
* Edits an application command.
|
||||||
* @param {ApplicationCommandResolvable} command The command to edit
|
* @param {ApplicationCommandResolvable} command The command to edit
|
||||||
* @param {ApplicationCommandData|APIApplicationCommand} data The data to update the command with
|
* @param {Partial<ApplicationCommandDataResolvable>} data The data to update the command with
|
||||||
* @param {Snowflake} [guildId] The guild's id where the command registered,
|
* @param {Snowflake} [guildId] The guild's id where the command registered,
|
||||||
* ignored when using a {@link GuildApplicationCommandManager}
|
* ignored when using a {@link GuildApplicationCommandManager}
|
||||||
* @returns {Promise<ApplicationCommand>}
|
* @returns {Promise<ApplicationCommand>}
|
||||||
@@ -199,19 +215,50 @@ class ApplicationCommandManager extends CachedManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms an {@link ApplicationCommandData} object into something that can be used with the API.
|
* Transforms an {@link ApplicationCommandData} object into something that can be used with the API.
|
||||||
* @param {ApplicationCommandData|APIApplicationCommand} command The command to transform
|
* @param {ApplicationCommandDataResolvable} command The command to transform
|
||||||
* @returns {APIApplicationCommand}
|
* @returns {APIApplicationCommand}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
static transformCommand(command) {
|
static transformCommand(command) {
|
||||||
|
if (isJSONEncodable(command)) return command.toJSON();
|
||||||
|
|
||||||
|
let default_member_permissions;
|
||||||
|
|
||||||
|
if ('default_member_permissions' in command) {
|
||||||
|
default_member_permissions = command.default_member_permissions
|
||||||
|
? new Permissions(BigInt(command.default_member_permissions)).bitfield.toString()
|
||||||
|
: command.default_member_permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('defaultMemberPermissions' in command) {
|
||||||
|
default_member_permissions =
|
||||||
|
command.defaultMemberPermissions !== null
|
||||||
|
? new Permissions(command.defaultMemberPermissions).bitfield.toString()
|
||||||
|
: command.defaultMemberPermissions;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: command.name,
|
name: command.name,
|
||||||
|
name_localizations: command.nameLocalizations ?? command.name_localizations,
|
||||||
description: command.description,
|
description: command.description,
|
||||||
|
description_localizations: command.descriptionLocalizations ?? command.description_localizations,
|
||||||
type: typeof command.type === 'number' ? command.type : ApplicationCommandTypes[command.type],
|
type: typeof command.type === 'number' ? command.type : ApplicationCommandTypes[command.type],
|
||||||
options: command.options?.map(o => ApplicationCommand.transformOption(o)),
|
options: command.options?.map(o => ApplicationCommand.transformOption(o)),
|
||||||
default_permission: command.defaultPermission ?? command.default_permission,
|
default_permission: command.defaultPermission ?? command.default_permission,
|
||||||
|
default_member_permissions,
|
||||||
|
dm_permission: command.dmPermission ?? command.dm_permission,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ApplicationCommandManager;
|
module.exports = ApplicationCommandManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @external SlashCommandBuilder
|
||||||
|
* @see {@link https://discord.js.org/#/docs/builders/main/class/SlashCommandBuilder}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @external ContextMenuCommandBuilder
|
||||||
|
* @see {@link https://discord.js.org/#/docs/builders/main/class/ContextMenuCommandBuilder}
|
||||||
|
*/
|
||||||
|
|||||||
@@ -54,9 +54,12 @@ class GuildBanManager extends CachedManager {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options used to fetch all bans from a guild.
|
* Options used to fetch multiple bans from a guild.
|
||||||
* @typedef {Object} FetchBansOptions
|
* @typedef {Object} FetchBansOptions
|
||||||
* @property {boolean} cache Whether or not to cache the fetched bans
|
* @property {number} [limit] The maximum number of bans to return
|
||||||
|
* @property {Snowflake} [before] Consider only bans before this id
|
||||||
|
* @property {Snowflake} [after] Consider only bans after this id
|
||||||
|
* @property {boolean} [cache] Whether to cache the fetched bans
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,13 +67,13 @@ class GuildBanManager extends CachedManager {
|
|||||||
* @param {UserResolvable|FetchBanOptions|FetchBansOptions} [options] Options for fetching guild ban(s)
|
* @param {UserResolvable|FetchBanOptions|FetchBansOptions} [options] Options for fetching guild ban(s)
|
||||||
* @returns {Promise<GuildBan|Collection<Snowflake, GuildBan>>}
|
* @returns {Promise<GuildBan|Collection<Snowflake, GuildBan>>}
|
||||||
* @example
|
* @example
|
||||||
* // Fetch all bans from a guild
|
* // Fetch multiple bans from a guild
|
||||||
* guild.bans.fetch()
|
* guild.bans.fetch()
|
||||||
* .then(console.log)
|
* .then(console.log)
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
* @example
|
* @example
|
||||||
* // Fetch all bans from a guild without caching
|
* // Fetch a maximum of 5 bans from a guild without caching
|
||||||
* guild.bans.fetch({ cache: false })
|
* guild.bans.fetch({ limit: 5, cache: false })
|
||||||
* .then(console.log)
|
* .then(console.log)
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
* @example
|
* @example
|
||||||
@@ -91,14 +94,15 @@ class GuildBanManager extends CachedManager {
|
|||||||
*/
|
*/
|
||||||
fetch(options) {
|
fetch(options) {
|
||||||
if (!options) return this._fetchMany();
|
if (!options) return this._fetchMany();
|
||||||
const user = this.client.users.resolveId(options);
|
const { user, cache, force, limit, before, after } = options;
|
||||||
if (user) return this._fetchSingle({ user, cache: true });
|
const resolvedUser = this.client.users.resolveId(user ?? options);
|
||||||
options.user &&= this.client.users.resolveId(options.user);
|
if (resolvedUser) return this._fetchSingle({ user: resolvedUser, cache, force });
|
||||||
if (!options.user) {
|
|
||||||
if ('cache' in options) return this._fetchMany(options.cache);
|
if (!before && !after && !limit && typeof cache === 'undefined') {
|
||||||
return Promise.reject(new Error('FETCH_BAN_RESOLVE_ID'));
|
return Promise.reject(new Error('FETCH_BAN_RESOLVE_ID'));
|
||||||
}
|
}
|
||||||
return this._fetchSingle(options);
|
|
||||||
|
return this._fetchMany(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _fetchSingle({ user, cache, force = false }) {
|
async _fetchSingle({ user, cache, force = false }) {
|
||||||
@@ -111,11 +115,13 @@ class GuildBanManager extends CachedManager {
|
|||||||
return this._add(data, cache);
|
return this._add(data, cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _fetchMany(cache) {
|
async _fetchMany(options = {}) {
|
||||||
const data = await this.client.api.guilds(this.guild.id).bans.get();
|
const data = await this.client.api.guilds(this.guild.id).bans.get({
|
||||||
return data.reduce((col, ban) => col.set(ban.user.id, this._add(ban, cache)), new Collection());
|
query: options,
|
||||||
}
|
});
|
||||||
|
|
||||||
|
return data.reduce((col, ban) => col.set(ban.user.id, this._add(ban, options.cache)), new Collection());
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Options used to ban a user from a guild.
|
* Options used to ban a user from a guild.
|
||||||
* @typedef {Object} BanOptions
|
* @typedef {Object} BanOptions
|
||||||
|
|||||||
@@ -4,11 +4,15 @@ const process = require('node:process');
|
|||||||
const { Collection } = require('@discordjs/collection');
|
const { Collection } = require('@discordjs/collection');
|
||||||
const CachedManager = require('./CachedManager');
|
const CachedManager = require('./CachedManager');
|
||||||
const ThreadManager = require('./ThreadManager');
|
const ThreadManager = require('./ThreadManager');
|
||||||
const { Error } = require('../errors');
|
const { Error, TypeError } = require('../errors');
|
||||||
const GuildChannel = require('../structures/GuildChannel');
|
const GuildChannel = require('../structures/GuildChannel');
|
||||||
const PermissionOverwrites = require('../structures/PermissionOverwrites');
|
const PermissionOverwrites = require('../structures/PermissionOverwrites');
|
||||||
const ThreadChannel = require('../structures/ThreadChannel');
|
const ThreadChannel = require('../structures/ThreadChannel');
|
||||||
const { ChannelTypes, ThreadChannelTypes } = require('../util/Constants');
|
const Webhook = require('../structures/Webhook');
|
||||||
|
const { ThreadChannelTypes, ChannelTypes, VideoQualityModes } = require('../util/Constants');
|
||||||
|
const DataResolver = require('../util/DataResolver');
|
||||||
|
const Util = require('../util/Util');
|
||||||
|
const { resolveAutoArchiveMaxLimit } = require('../util/Util');
|
||||||
|
|
||||||
let cacheWarningEmitted = false;
|
let cacheWarningEmitted = false;
|
||||||
let storeChannelDeprecationEmitted = false;
|
let storeChannelDeprecationEmitted = false;
|
||||||
@@ -169,6 +173,153 @@ class GuildChannelManager extends CachedManager {
|
|||||||
return this.client.actions.ChannelCreate.handle(data).channel;
|
return this.client.actions.ChannelCreate.handle(data).channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a webhook for the channel.
|
||||||
|
* @param {GuildChannelResolvable} channel The channel to create the webhook for
|
||||||
|
* @param {string} name The name of the webhook
|
||||||
|
* @param {ChannelWebhookCreateOptions} [options] Options for creating the webhook
|
||||||
|
* @returns {Promise<Webhook>} Returns the created Webhook
|
||||||
|
* @example
|
||||||
|
* // Create a webhook for the current channel
|
||||||
|
* guild.channels.createWebhook('222197033908436994', 'Snek', {
|
||||||
|
* avatar: 'https://i.imgur.com/mI8XcpG.jpg',
|
||||||
|
* reason: 'Needed a cool new Webhook'
|
||||||
|
* })
|
||||||
|
* .then(console.log)
|
||||||
|
* .catch(console.error)
|
||||||
|
*/
|
||||||
|
async createWebhook(channel, name, { avatar, reason } = {}) {
|
||||||
|
const id = this.resolveId(channel);
|
||||||
|
if (!id) throw new TypeError('INVALID_TYPE', 'channel', 'GuildChannelResolvable');
|
||||||
|
if (typeof avatar === 'string' && !avatar.startsWith('data:')) {
|
||||||
|
avatar = await DataResolver.resolveImage(avatar);
|
||||||
|
}
|
||||||
|
const data = await this.client.api.channels[id].webhooks.post({
|
||||||
|
data: {
|
||||||
|
name,
|
||||||
|
avatar,
|
||||||
|
},
|
||||||
|
reason,
|
||||||
|
});
|
||||||
|
return new Webhook(this.client, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data for a guild channel.
|
||||||
|
* @typedef {Object} ChannelData
|
||||||
|
* @property {string} [name] The name of the channel
|
||||||
|
* @property {ChannelType} [type] The type of the channel (only conversion between text and news is supported)
|
||||||
|
* @property {number} [position] The position of the channel
|
||||||
|
* @property {string} [topic] The topic of the text channel
|
||||||
|
* @property {boolean} [nsfw] Whether the channel is NSFW
|
||||||
|
* @property {number} [bitrate] The bitrate of the voice channel
|
||||||
|
* @property {number} [userLimit] The user limit of the voice channel
|
||||||
|
* @property {?CategoryChannelResolvable} [parent] The parent of the channel
|
||||||
|
* @property {boolean} [lockPermissions]
|
||||||
|
* Lock the permissions of the channel to what the parent's permissions are
|
||||||
|
* @property {OverwriteResolvable[]|Collection<Snowflake, OverwriteResolvable>} [permissionOverwrites]
|
||||||
|
* Permission overwrites for the channel
|
||||||
|
* @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the channel in seconds
|
||||||
|
* @property {ThreadAutoArchiveDuration} [defaultAutoArchiveDuration]
|
||||||
|
* The default auto archive duration for all new threads in this channel
|
||||||
|
* @property {?string} [rtcRegion] The RTC region of the channel
|
||||||
|
* @property {?VideoQualityMode|number} [videoQualityMode] The camera video quality mode of the channel
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edits the channel.
|
||||||
|
* @param {GuildChannelResolvable} channel The channel to edit
|
||||||
|
* @param {ChannelData} data The new data for the channel
|
||||||
|
* @param {string} [reason] Reason for editing this channel
|
||||||
|
* @returns {Promise<GuildChannel>}
|
||||||
|
* @example
|
||||||
|
* // Edit a channel
|
||||||
|
* guild.channels.edit('222197033908436994', { name: 'new-channel' })
|
||||||
|
* .then(console.log)
|
||||||
|
* .catch(console.error);
|
||||||
|
*/
|
||||||
|
async edit(channel, data, reason) {
|
||||||
|
channel = this.resolve(channel);
|
||||||
|
if (!channel) throw new TypeError('INVALID_TYPE', 'channel', 'GuildChannelResolvable');
|
||||||
|
|
||||||
|
const parent = data.parent && this.client.channels.resolveId(data.parent);
|
||||||
|
|
||||||
|
if (typeof data.position !== 'undefined') await this.setPosition(channel, data.position, { reason });
|
||||||
|
|
||||||
|
let permission_overwrites = data.permissionOverwrites?.map(o => PermissionOverwrites.resolve(o, this.guild));
|
||||||
|
|
||||||
|
if (data.lockPermissions) {
|
||||||
|
if (parent) {
|
||||||
|
const newParent = this.guild.channels.resolve(parent);
|
||||||
|
if (newParent?.type === 'GUILD_CATEGORY') {
|
||||||
|
permission_overwrites = newParent.permissionOverwrites.cache.map(o =>
|
||||||
|
PermissionOverwrites.resolve(o, this.guild),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (channel.parent) {
|
||||||
|
permission_overwrites = channel.parent.permissionOverwrites.cache.map(o =>
|
||||||
|
PermissionOverwrites.resolve(o, this.guild),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let defaultAutoArchiveDuration = data.defaultAutoArchiveDuration;
|
||||||
|
if (defaultAutoArchiveDuration === 'MAX') defaultAutoArchiveDuration = resolveAutoArchiveMaxLimit(this.guild);
|
||||||
|
|
||||||
|
const newData = await this.client.api.channels(channel.id).patch({
|
||||||
|
data: {
|
||||||
|
name: (data.name ?? channel.name).trim(),
|
||||||
|
type: data.type,
|
||||||
|
topic: data.topic,
|
||||||
|
nsfw: data.nsfw,
|
||||||
|
bitrate: data.bitrate ?? channel.bitrate,
|
||||||
|
user_limit: data.userLimit ?? channel.userLimit,
|
||||||
|
rtc_region: 'rtcRegion' in data ? data.rtcRegion : channel.rtcRegion,
|
||||||
|
video_quality_mode:
|
||||||
|
typeof data.videoQualityMode === 'string' ? VideoQualityModes[data.videoQualityMode] : data.videoQualityMode,
|
||||||
|
parent_id: parent,
|
||||||
|
lock_permissions: data.lockPermissions,
|
||||||
|
rate_limit_per_user: data.rateLimitPerUser,
|
||||||
|
default_auto_archive_duration: defaultAutoArchiveDuration,
|
||||||
|
permission_overwrites,
|
||||||
|
},
|
||||||
|
reason,
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.client.actions.ChannelUpdate.handle(newData).updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a new position for the guild channel.
|
||||||
|
* @param {GuildChannelResolvable} channel The channel to set the position for
|
||||||
|
* @param {number} position The new position for the guild channel
|
||||||
|
* @param {SetChannelPositionOptions} [options] Options for setting position
|
||||||
|
* @returns {Promise<GuildChannel>}
|
||||||
|
* @example
|
||||||
|
* // Set a new channel position
|
||||||
|
* guild.channels.setPosition('222078374472843266', 2)
|
||||||
|
* .then(newChannel => console.log(`Channel's new position is ${newChannel.position}`))
|
||||||
|
* .catch(console.error);
|
||||||
|
*/
|
||||||
|
async setPosition(channel, position, { relative, reason } = {}) {
|
||||||
|
channel = this.resolve(channel);
|
||||||
|
if (!channel) throw new TypeError('INVALID_TYPE', 'channel', 'GuildChannelResolvable');
|
||||||
|
const updatedChannels = await Util.setPosition(
|
||||||
|
channel,
|
||||||
|
position,
|
||||||
|
relative,
|
||||||
|
this.guild._sortedChannels(channel),
|
||||||
|
this.client.api.guilds(this.guild.id).channels,
|
||||||
|
reason,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.client.actions.GuildChannelsPositionUpdate.handle({
|
||||||
|
guild_id: this.guild.id,
|
||||||
|
channels: updatedChannels,
|
||||||
|
});
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains one or more guild channels from Discord, or the channel cache if they're already available.
|
* Obtains one or more guild channels from Discord, or the channel cache if they're already available.
|
||||||
* @param {Snowflake} [id] The channel's id
|
* @param {Snowflake} [id] The channel's id
|
||||||
@@ -204,6 +355,39 @@ class GuildChannelManager extends CachedManager {
|
|||||||
return channels;
|
return channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches all webhooks for the channel.
|
||||||
|
* @param {GuildChannelResolvable} channel The channel to fetch webhooks for
|
||||||
|
* @returns {Promise<Collection<Snowflake, Webhook>>}
|
||||||
|
* @example
|
||||||
|
* // Fetch webhooks
|
||||||
|
* guild.channels.fetchWebhooks('769862166131245066')
|
||||||
|
* .then(hooks => console.log(`This channel has ${hooks.size} hooks`))
|
||||||
|
* .catch(console.error);
|
||||||
|
*/
|
||||||
|
async fetchWebhooks(channel) {
|
||||||
|
const id = this.resolveId(channel);
|
||||||
|
if (!id) throw new TypeError('INVALID_TYPE', 'channel', 'GuildChannelResolvable');
|
||||||
|
const data = await this.client.api.channels[id].webhooks.get();
|
||||||
|
return data.reduce((hooks, hook) => hooks.set(hook.id, new Webhook(this.client, hook)), new Collection());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data that can be resolved to give a Category Channel object. This can be:
|
||||||
|
* * A CategoryChannel object
|
||||||
|
* * A Snowflake
|
||||||
|
* @typedef {CategoryChannel|Snowflake} CategoryChannelResolvable
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data needed for updating a channel's position.
|
||||||
|
* @typedef {Object} ChannelPosition
|
||||||
|
* @property {GuildChannel|Snowflake} channel Channel to update
|
||||||
|
* @property {number} [position] New position for the channel
|
||||||
|
* @property {CategoryChannelResolvable} [parent] Parent channel for this channel
|
||||||
|
* @property {boolean} [lockPermissions] If the overwrites should be locked to the parents overwrites
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Batch-updates the guild's channels' positions.
|
* Batch-updates the guild's channels' positions.
|
||||||
* <info>Only one channel's parent can be changed at a time</info>
|
* <info>Only one channel's parent can be changed at a time</info>
|
||||||
@@ -219,7 +403,7 @@ class GuildChannelManager extends CachedManager {
|
|||||||
id: this.client.channels.resolveId(r.channel),
|
id: this.client.channels.resolveId(r.channel),
|
||||||
position: r.position,
|
position: r.position,
|
||||||
lock_permissions: r.lockPermissions,
|
lock_permissions: r.lockPermissions,
|
||||||
parent_id: typeof r.parent !== 'undefined' ? this.channels.resolveId(r.parent) : undefined,
|
parent_id: typeof r.parent !== 'undefined' ? this.resolveId(r.parent) : undefined,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await this.client.api.guilds(this.guild.id).channels.patch({ data: channelPositions });
|
await this.client.api.guilds(this.guild.id).channels.patch({ data: channelPositions });
|
||||||
@@ -243,6 +427,23 @@ class GuildChannelManager extends CachedManager {
|
|||||||
const raw = await this.client.api.guilds(this.guild.id).threads.active.get();
|
const raw = await this.client.api.guilds(this.guild.id).threads.active.get();
|
||||||
return ThreadManager._mapThreads(raw, this.client, { guild: this.guild, cache });
|
return ThreadManager._mapThreads(raw, this.client, { guild: this.guild, cache });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the channel.
|
||||||
|
* @param {GuildChannelResolvable} channel The channel to delete
|
||||||
|
* @param {string} [reason] Reason for deleting this channel
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
* @example
|
||||||
|
* // Delete the channel
|
||||||
|
* guild.channels.delete('858850993013260338', 'making room for new channels')
|
||||||
|
* .then(console.log)
|
||||||
|
* .catch(console.error);
|
||||||
|
*/
|
||||||
|
async delete(channel, reason) {
|
||||||
|
const id = this.resolveId(channel);
|
||||||
|
if (!id) throw new TypeError('INVALID_TYPE', 'channel', 'GuildChannelResolvable');
|
||||||
|
await this.client.api.channels(id).delete({ reason });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = GuildChannelManager;
|
module.exports = GuildChannelManager;
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
const { Collection } = require('@discordjs/collection');
|
const { Collection } = require('@discordjs/collection');
|
||||||
const BaseGuildEmojiManager = require('./BaseGuildEmojiManager');
|
const BaseGuildEmojiManager = require('./BaseGuildEmojiManager');
|
||||||
const { TypeError } = require('../errors');
|
const { Error, TypeError } = require('../errors');
|
||||||
const DataResolver = require('../util/DataResolver');
|
const DataResolver = require('../util/DataResolver');
|
||||||
|
const Permissions = require('../util/Permissions');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages API methods for GuildEmojis and stores their cache.
|
* Manages API methods for GuildEmojis and stores their cache.
|
||||||
@@ -100,6 +101,71 @@ class GuildEmojiManager extends BaseGuildEmojiManager {
|
|||||||
for (const emoji of data) emojis.set(emoji.id, this._add(emoji, cache));
|
for (const emoji of data) emojis.set(emoji.id, this._add(emoji, cache));
|
||||||
return emojis;
|
return emojis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an emoji.
|
||||||
|
* @param {EmojiResolvable} emoji The Emoji resolvable to delete
|
||||||
|
* @param {string} [reason] Reason for deleting the emoji
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async delete(emoji, reason) {
|
||||||
|
const id = this.resolveId(emoji);
|
||||||
|
if (!id) throw new TypeError('INVALID_TYPE', 'emoji', 'EmojiResolvable', true);
|
||||||
|
await this.client.api.guilds(this.guild.id).emojis(id).delete({ reason });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edits an emoji.
|
||||||
|
* @param {EmojiResolvable} emoji The Emoji resolvable to edit
|
||||||
|
* @param {GuildEmojiEditData} data The new data for the emoji
|
||||||
|
* @param {string} [reason] Reason for editing this emoji
|
||||||
|
* @returns {Promise<GuildEmoji>}
|
||||||
|
*/
|
||||||
|
async edit(emoji, data, reason) {
|
||||||
|
const id = this.resolveId(emoji);
|
||||||
|
if (!id) throw new TypeError('INVALID_TYPE', 'emoji', 'EmojiResolvable', true);
|
||||||
|
const roles = data.roles?.map(r => this.guild.roles.resolveId(r));
|
||||||
|
const newData = await this.client.api
|
||||||
|
.guilds(this.guild.id)
|
||||||
|
.emojis(id)
|
||||||
|
.patch({
|
||||||
|
data: {
|
||||||
|
name: data.name,
|
||||||
|
roles,
|
||||||
|
},
|
||||||
|
reason,
|
||||||
|
});
|
||||||
|
const existing = this.cache.get(id);
|
||||||
|
if (existing) {
|
||||||
|
const clone = existing._clone();
|
||||||
|
clone._patch(newData);
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
return this._add(newData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the author for this emoji
|
||||||
|
* @param {EmojiResolvable} emoji The emoji to fetch the author of
|
||||||
|
* @returns {Promise<User>}
|
||||||
|
*/
|
||||||
|
async fetchAuthor(emoji) {
|
||||||
|
emoji = this.resolve(emoji);
|
||||||
|
if (!emoji) throw new TypeError('INVALID_TYPE', 'emoji', 'EmojiResolvable', true);
|
||||||
|
if (emoji.managed) {
|
||||||
|
throw new Error('EMOJI_MANAGED');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { me } = this.guild;
|
||||||
|
if (!me) throw new Error('GUILD_UNCACHED_ME');
|
||||||
|
if (!me.permissions.has(Permissions.FLAGS.MANAGE_EMOJIS_AND_STICKERS)) {
|
||||||
|
throw new Error('MISSING_MANAGE_EMOJIS_AND_STICKERS_PERMISSION', this.guild);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await this.client.api.guilds(this.guild.id).emojis(emoji.id).get();
|
||||||
|
emoji._patch(data);
|
||||||
|
return emoji.author;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = GuildEmojiManager;
|
module.exports = GuildEmojiManager;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ const {
|
|||||||
VerificationLevels,
|
VerificationLevels,
|
||||||
DefaultMessageNotificationLevels,
|
DefaultMessageNotificationLevels,
|
||||||
ExplicitContentFilterLevels,
|
ExplicitContentFilterLevels,
|
||||||
|
VideoQualityModes,
|
||||||
} = require('../util/Constants');
|
} = require('../util/Constants');
|
||||||
const DataResolver = require('../util/DataResolver');
|
const DataResolver = require('../util/DataResolver');
|
||||||
const Permissions = require('../util/Permissions');
|
const Permissions = require('../util/Permissions');
|
||||||
@@ -94,6 +95,7 @@ class GuildManager extends CachedManager {
|
|||||||
* @property {number} [bitrate] The bitrate of the voice channel
|
* @property {number} [bitrate] The bitrate of the voice channel
|
||||||
* @property {number} [userLimit] The user limit of the channel
|
* @property {number} [userLimit] The user limit of the channel
|
||||||
* @property {?string} [rtcRegion] The RTC region of the channel
|
* @property {?string} [rtcRegion] The RTC region of the channel
|
||||||
|
* @property {VideoQualityMode|number} [videoQualityMode] The camera video quality mode of the channel
|
||||||
* @property {PartialOverwriteData[]} [permissionOverwrites]
|
* @property {PartialOverwriteData[]} [permissionOverwrites]
|
||||||
* Overwrites of the channel
|
* Overwrites of the channel
|
||||||
* @property {number} [rateLimitPerUser] The rate limit per user (slowmode) of the channel in seconds
|
* @property {number} [rateLimitPerUser] The rate limit per user (slowmode) of the channel in seconds
|
||||||
@@ -200,6 +202,11 @@ class GuildManager extends CachedManager {
|
|||||||
delete channel.rateLimitPerUser;
|
delete channel.rateLimitPerUser;
|
||||||
channel.rtc_region = channel.rtcRegion;
|
channel.rtc_region = channel.rtcRegion;
|
||||||
delete channel.rtcRegion;
|
delete channel.rtcRegion;
|
||||||
|
channel.video_quality_mode =
|
||||||
|
typeof channel.videoQualityMode === 'string'
|
||||||
|
? VideoQualityModes[channel.videoQualityMode]
|
||||||
|
: channel.videoQualityMode;
|
||||||
|
delete channel.videoQualityMode;
|
||||||
|
|
||||||
if (!channel.permissionOverwrites) continue;
|
if (!channel.permissionOverwrites) continue;
|
||||||
for (const overwrite of channel.permissionOverwrites) {
|
for (const overwrite of channel.permissionOverwrites) {
|
||||||
|
|||||||
@@ -353,7 +353,7 @@ class GuildMemberManager extends CachedManager {
|
|||||||
* @example
|
* @example
|
||||||
* // Kick a user by id (or with a user/guild member object)
|
* // Kick a user by id (or with a user/guild member object)
|
||||||
* guild.members.kick('84484653687267328')
|
* guild.members.kick('84484653687267328')
|
||||||
* .then(banInfo => console.log(`Kicked ${banInfo.user?.tag ?? banInfo.tag ?? banInfo}`))
|
* .then(kickInfo => console.log(`Kicked ${kickInfo.user?.tag ?? kickInfo.tag ?? kickInfo}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
async kick(user, reason) {
|
async kick(user, reason) {
|
||||||
@@ -376,7 +376,7 @@ class GuildMemberManager extends CachedManager {
|
|||||||
* @example
|
* @example
|
||||||
* // Ban a user by id (or with a user/guild member object)
|
* // Ban a user by id (or with a user/guild member object)
|
||||||
* guild.members.ban('84484653687267328')
|
* guild.members.ban('84484653687267328')
|
||||||
* .then(kickInfo => console.log(`Banned ${kickInfo.user?.tag ?? kickInfo.tag ?? kickInfo}`))
|
* .then(banInfo => console.log(`Banned ${banInfo.user?.tag ?? banInfo.tag ?? banInfo}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
ban(user, options = { days: 0 }) {
|
ban(user, options = { days: 0 }) {
|
||||||
@@ -387,7 +387,7 @@ class GuildMemberManager extends CachedManager {
|
|||||||
* Unbans a user from the guild. Internally calls the {@link GuildBanManager#remove} method.
|
* Unbans a user from the guild. Internally calls the {@link GuildBanManager#remove} method.
|
||||||
* @param {UserResolvable} user The user to unban
|
* @param {UserResolvable} user The user to unban
|
||||||
* @param {string} [reason] Reason for unbanning user
|
* @param {string} [reason] Reason for unbanning user
|
||||||
* @returns {Promise<User>} The user that was unbanned
|
* @returns {Promise<?User>} The user that was unbanned
|
||||||
* @example
|
* @example
|
||||||
* // Unban a user by id (or with a user/guild member object)
|
* // Unban a user by id (or with a user/guild member object)
|
||||||
* guild.members.unban('84484653687267328')
|
* guild.members.unban('84484653687267328')
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const CachedManager = require('./CachedManager');
|
|||||||
const { TypeError, Error } = require('../errors');
|
const { TypeError, Error } = require('../errors');
|
||||||
const { GuildScheduledEvent } = require('../structures/GuildScheduledEvent');
|
const { GuildScheduledEvent } = require('../structures/GuildScheduledEvent');
|
||||||
const { PrivacyLevels, GuildScheduledEventEntityTypes, GuildScheduledEventStatuses } = require('../util/Constants');
|
const { PrivacyLevels, GuildScheduledEventEntityTypes, GuildScheduledEventStatuses } = require('../util/Constants');
|
||||||
|
const DataResolver = require('../util/DataResolver');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages API methods for GuildScheduledEvents and stores their cache.
|
* Manages API methods for GuildScheduledEvents and stores their cache.
|
||||||
@@ -49,6 +50,7 @@ class GuildScheduledEventManager extends CachedManager {
|
|||||||
* @property {GuildScheduledEventEntityMetadataOptions} [entityMetadata] The entity metadata of the
|
* @property {GuildScheduledEventEntityMetadataOptions} [entityMetadata] The entity metadata of the
|
||||||
* guild scheduled event
|
* guild scheduled event
|
||||||
* <warn>This is required if `entityType` is 'EXTERNAL'</warn>
|
* <warn>This is required if `entityType` is 'EXTERNAL'</warn>
|
||||||
|
* @property {?(BufferResolvable|Base64Resolvable)} [image] The cover image of the guild scheduled event
|
||||||
* @property {string} [reason] The reason for creating the guild scheduled event
|
* @property {string} [reason] The reason for creating the guild scheduled event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -76,6 +78,7 @@ class GuildScheduledEventManager extends CachedManager {
|
|||||||
scheduledEndTime,
|
scheduledEndTime,
|
||||||
entityMetadata,
|
entityMetadata,
|
||||||
reason,
|
reason,
|
||||||
|
image,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
if (typeof privacyLevel === 'string') privacyLevel = PrivacyLevels[privacyLevel];
|
if (typeof privacyLevel === 'string') privacyLevel = PrivacyLevels[privacyLevel];
|
||||||
@@ -99,6 +102,7 @@ class GuildScheduledEventManager extends CachedManager {
|
|||||||
scheduled_start_time: new Date(scheduledStartTime).toISOString(),
|
scheduled_start_time: new Date(scheduledStartTime).toISOString(),
|
||||||
scheduled_end_time: scheduledEndTime ? new Date(scheduledEndTime).toISOString() : scheduledEndTime,
|
scheduled_end_time: scheduledEndTime ? new Date(scheduledEndTime).toISOString() : scheduledEndTime,
|
||||||
description,
|
description,
|
||||||
|
image: image && (await DataResolver.resolveImage(image)),
|
||||||
entity_type: entityType,
|
entity_type: entityType,
|
||||||
entity_metadata,
|
entity_metadata,
|
||||||
},
|
},
|
||||||
@@ -172,6 +176,7 @@ class GuildScheduledEventManager extends CachedManager {
|
|||||||
* @property {GuildScheduledEventEntityMetadataOptions} [entityMetadata] The entity metadata of the
|
* @property {GuildScheduledEventEntityMetadataOptions} [entityMetadata] The entity metadata of the
|
||||||
* guild scheduled event
|
* guild scheduled event
|
||||||
* <warn>This can be modified only if `entityType` of the `GuildScheduledEvent` to be edited is 'EXTERNAL'</warn>
|
* <warn>This can be modified only if `entityType` of the `GuildScheduledEvent` to be edited is 'EXTERNAL'</warn>
|
||||||
|
* @property {?(BufferResolvable|Base64Resolvable)} [image] The cover image of the guild scheduled event
|
||||||
* @property {string} [reason] The reason for editing the guild scheduled event
|
* @property {string} [reason] The reason for editing the guild scheduled event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -197,6 +202,7 @@ class GuildScheduledEventManager extends CachedManager {
|
|||||||
scheduledEndTime,
|
scheduledEndTime,
|
||||||
entityMetadata,
|
entityMetadata,
|
||||||
reason,
|
reason,
|
||||||
|
image,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
if (typeof privacyLevel === 'string') privacyLevel = PrivacyLevels[privacyLevel];
|
if (typeof privacyLevel === 'string') privacyLevel = PrivacyLevels[privacyLevel];
|
||||||
@@ -220,6 +226,7 @@ class GuildScheduledEventManager extends CachedManager {
|
|||||||
description,
|
description,
|
||||||
entity_type: entityType,
|
entity_type: entityType,
|
||||||
status,
|
status,
|
||||||
|
image: image && (await DataResolver.resolveImage(image)),
|
||||||
entity_metadata,
|
entity_metadata,
|
||||||
},
|
},
|
||||||
reason,
|
reason,
|
||||||
|
|||||||
@@ -161,6 +161,19 @@ class GuildStickerManager extends CachedManager {
|
|||||||
const data = await this.client.api.guilds(this.guild.id).stickers.get();
|
const data = await this.client.api.guilds(this.guild.id).stickers.get();
|
||||||
return new Collection(data.map(sticker => [sticker.id, this._add(sticker, cache)]));
|
return new Collection(data.map(sticker => [sticker.id, this._add(sticker, cache)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the user who uploaded this sticker, if this is a guild sticker.
|
||||||
|
* @param {StickerResolvable} sticker The sticker to fetch the user for
|
||||||
|
* @returns {Promise<?User>}
|
||||||
|
*/
|
||||||
|
async fetchUser(sticker) {
|
||||||
|
sticker = this.resolve(sticker);
|
||||||
|
if (!sticker) throw new TypeError('INVALID_TYPE', 'sticker', 'StickerResolvable');
|
||||||
|
const data = await this.client.api.guilds(this.guild.id).stickers(sticker.id).get();
|
||||||
|
sticker._patch(data);
|
||||||
|
return sticker.user;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = GuildStickerManager;
|
module.exports = GuildStickerManager;
|
||||||
|
|||||||
@@ -156,25 +156,27 @@ class MessageManager extends CachedManager {
|
|||||||
/**
|
/**
|
||||||
* Pins a message to the channel's pinned messages, even if it's not cached.
|
* Pins a message to the channel's pinned messages, even if it's not cached.
|
||||||
* @param {MessageResolvable} message The message to pin
|
* @param {MessageResolvable} message The message to pin
|
||||||
|
* @param {string} [reason] Reason for pinning
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async pin(message) {
|
async pin(message, reason) {
|
||||||
message = this.resolveId(message);
|
message = this.resolveId(message);
|
||||||
if (!message) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');
|
if (!message) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');
|
||||||
|
|
||||||
await this.client.api.channels(this.channel.id).pins(message).put();
|
await this.client.api.channels(this.channel.id).pins(message).put({ reason });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unpins a message from the channel's pinned messages, even if it's not cached.
|
* Unpins a message from the channel's pinned messages, even if it's not cached.
|
||||||
* @param {MessageResolvable} message The message to unpin
|
* @param {MessageResolvable} message The message to unpin
|
||||||
|
* @param {string} [reason] Reason for unpinning
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async unpin(message) {
|
async unpin(message, reason) {
|
||||||
message = this.resolveId(message);
|
message = this.resolveId(message);
|
||||||
if (!message) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');
|
if (!message) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');
|
||||||
|
|
||||||
await this.client.api.channels(this.channel.id).pins(message).delete();
|
await this.client.api.channels(this.channel.id).pins(message).delete({ reason });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -142,8 +142,9 @@ class PermissionOverwriteManager extends CachedManager {
|
|||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
edit(userOrRole, options, overwriteOptions) {
|
edit(userOrRole, options, overwriteOptions) {
|
||||||
userOrRole = this.channel.guild.roles.resolveId(userOrRole) ?? this.client.users.resolveId(userOrRole);
|
const existing = this.cache.get(
|
||||||
const existing = this.cache.get(userOrRole);
|
this.channel.guild.roles.resolveId(userOrRole) ?? this.client.users.resolveId(userOrRole),
|
||||||
|
);
|
||||||
return this.upsert(userOrRole, options, overwriteOptions, existing);
|
return this.upsert(userOrRole, options, overwriteOptions, existing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ const { TypeError } = require('../errors');
|
|||||||
const { Role } = require('../structures/Role');
|
const { Role } = require('../structures/Role');
|
||||||
const DataResolver = require('../util/DataResolver');
|
const DataResolver = require('../util/DataResolver');
|
||||||
const Permissions = require('../util/Permissions');
|
const Permissions = require('../util/Permissions');
|
||||||
const { resolveColor, setPosition } = require('../util/Util');
|
const { resolveColor } = require('../util/Util');
|
||||||
|
const Util = require('../util/Util');
|
||||||
|
|
||||||
let cacheWarningEmitted = false;
|
let cacheWarningEmitted = false;
|
||||||
|
|
||||||
@@ -159,7 +160,7 @@ class RoleManager extends CachedManager {
|
|||||||
guild_id: this.guild.id,
|
guild_id: this.guild.id,
|
||||||
role: data,
|
role: data,
|
||||||
});
|
});
|
||||||
if (position) return role.setPosition(position, reason);
|
if (position) return this.setPosition(role, position, { reason });
|
||||||
return role;
|
return role;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,21 +180,7 @@ class RoleManager extends CachedManager {
|
|||||||
role = this.resolve(role);
|
role = this.resolve(role);
|
||||||
if (!role) throw new TypeError('INVALID_TYPE', 'role', 'RoleResolvable');
|
if (!role) throw new TypeError('INVALID_TYPE', 'role', 'RoleResolvable');
|
||||||
|
|
||||||
if (typeof data.position === 'number') {
|
if (typeof data.position === 'number') await this.setPosition(role, data.position, { reason });
|
||||||
const updatedRoles = await setPosition(
|
|
||||||
role,
|
|
||||||
data.position,
|
|
||||||
false,
|
|
||||||
this.guild._sortedRoles(),
|
|
||||||
this.client.api.guilds(this.guild.id).roles,
|
|
||||||
reason,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.client.actions.GuildRolesPositionUpdate.handle({
|
|
||||||
guild_id: this.guild.id,
|
|
||||||
roles: updatedRoles,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let icon = data.icon;
|
let icon = data.icon;
|
||||||
if (icon) {
|
if (icon) {
|
||||||
@@ -227,7 +214,7 @@ class RoleManager extends CachedManager {
|
|||||||
* @example
|
* @example
|
||||||
* // Delete a role
|
* // Delete a role
|
||||||
* guild.roles.delete('222079219327434752', 'The role needed to go')
|
* guild.roles.delete('222079219327434752', 'The role needed to go')
|
||||||
* .then(deleted => console.log(`Deleted role ${deleted.name}`))
|
* .then(() => console.log('Deleted the role.'))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
async delete(role, reason) {
|
async delete(role, reason) {
|
||||||
@@ -236,6 +223,44 @@ class RoleManager extends CachedManager {
|
|||||||
this.client.actions.GuildRoleDelete.handle({ guild_id: this.guild.id, role_id: id });
|
this.client.actions.GuildRoleDelete.handle({ guild_id: this.guild.id, role_id: id });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the new position of the role.
|
||||||
|
* @param {RoleResolvable} role The role to change the position of
|
||||||
|
* @param {number} position The new position for the role
|
||||||
|
* @param {SetRolePositionOptions} [options] Options for setting the position
|
||||||
|
* @returns {Promise<Role>}
|
||||||
|
* @example
|
||||||
|
* // Set the position of the role
|
||||||
|
* guild.roles.setPosition('222197033908436994', 1)
|
||||||
|
* .then(updated => console.log(`Role position: ${updated.position}`))
|
||||||
|
* .catch(console.error);
|
||||||
|
*/
|
||||||
|
async setPosition(role, position, { relative, reason } = {}) {
|
||||||
|
role = this.resolve(role);
|
||||||
|
if (!role) throw new TypeError('INVALID_TYPE', 'role', 'RoleResolvable');
|
||||||
|
const updatedRoles = await Util.setPosition(
|
||||||
|
role,
|
||||||
|
position,
|
||||||
|
relative,
|
||||||
|
this.guild._sortedRoles(),
|
||||||
|
this.client.api.guilds(this.guild.id).roles,
|
||||||
|
reason,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.client.actions.GuildRolesPositionUpdate.handle({
|
||||||
|
guild_id: this.guild.id,
|
||||||
|
roles: updatedRoles,
|
||||||
|
});
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data needed for updating a guild role's position
|
||||||
|
* @typedef {Object} GuildRolePosition
|
||||||
|
* @property {RoleResolvable} role The role's id
|
||||||
|
* @property {number} position The position to update
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Batch-updates the guild's role positions
|
* Batch-updates the guild's role positions
|
||||||
* @param {GuildRolePosition[]} rolePositions Role positions to update
|
* @param {GuildRolePosition[]} rolePositions Role positions to update
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class StageInstanceManager extends CachedManager {
|
|||||||
* @typedef {Object} StageInstanceCreateOptions
|
* @typedef {Object} StageInstanceCreateOptions
|
||||||
* @property {string} topic The topic of the stage instance
|
* @property {string} topic The topic of the stage instance
|
||||||
* @property {PrivacyLevel|number} [privacyLevel] The privacy level of the stage instance
|
* @property {PrivacyLevel|number} [privacyLevel] The privacy level of the stage instance
|
||||||
|
* @property {boolean} [sendStartNotification] Whether to notify `@everyone` that the stage instance has started
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,7 +59,7 @@ class StageInstanceManager extends CachedManager {
|
|||||||
const channelId = this.guild.channels.resolveId(channel);
|
const channelId = this.guild.channels.resolveId(channel);
|
||||||
if (!channelId) throw new Error('STAGE_CHANNEL_RESOLVE');
|
if (!channelId) throw new Error('STAGE_CHANNEL_RESOLVE');
|
||||||
if (typeof options !== 'object') throw new TypeError('INVALID_TYPE', 'options', 'object', true);
|
if (typeof options !== 'object') throw new TypeError('INVALID_TYPE', 'options', 'object', true);
|
||||||
let { topic, privacyLevel } = options;
|
let { topic, privacyLevel, sendStartNotification } = options;
|
||||||
|
|
||||||
privacyLevel &&= typeof privacyLevel === 'number' ? privacyLevel : PrivacyLevels[privacyLevel];
|
privacyLevel &&= typeof privacyLevel === 'number' ? privacyLevel : PrivacyLevels[privacyLevel];
|
||||||
|
|
||||||
@@ -67,6 +68,7 @@ class StageInstanceManager extends CachedManager {
|
|||||||
channel_id: channelId,
|
channel_id: channelId,
|
||||||
topic,
|
topic,
|
||||||
privacy_level: privacyLevel,
|
privacy_level: privacyLevel,
|
||||||
|
send_start_notification: sendStartNotification,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const CachedManager = require('./CachedManager');
|
|||||||
const { TypeError } = require('../errors');
|
const { TypeError } = require('../errors');
|
||||||
const ThreadChannel = require('../structures/ThreadChannel');
|
const ThreadChannel = require('../structures/ThreadChannel');
|
||||||
const { ChannelTypes } = require('../util/Constants');
|
const { ChannelTypes } = require('../util/Constants');
|
||||||
|
const { resolveAutoArchiveMaxLimit } = require('../util/Util');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages API methods for {@link ThreadChannel} objects and stores their cache.
|
* Manages API methods for {@link ThreadChannel} objects and stores their cache.
|
||||||
@@ -120,14 +121,8 @@ class ThreadManager extends CachedManager {
|
|||||||
} else if (this.channel.type !== 'GUILD_NEWS') {
|
} else if (this.channel.type !== 'GUILD_NEWS') {
|
||||||
resolvedType = typeof type === 'string' ? ChannelTypes[type] : type ?? resolvedType;
|
resolvedType = typeof type === 'string' ? ChannelTypes[type] : type ?? resolvedType;
|
||||||
}
|
}
|
||||||
if (autoArchiveDuration === 'MAX') {
|
|
||||||
autoArchiveDuration = 1440;
|
if (autoArchiveDuration === 'MAX') autoArchiveDuration = resolveAutoArchiveMaxLimit(this.channel.guild);
|
||||||
if (this.channel.guild.features.includes('SEVEN_DAY_THREAD_ARCHIVE')) {
|
|
||||||
autoArchiveDuration = 10080;
|
|
||||||
} else if (this.channel.guild.features.includes('THREE_DAY_THREAD_ARCHIVE')) {
|
|
||||||
autoArchiveDuration = 4320;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await path.threads.post({
|
const data = await path.threads.post({
|
||||||
data: {
|
data: {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class RateLimitError extends Error {
|
|||||||
this.name = 'RateLimitError';
|
this.name = 'RateLimitError';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Time until this rate limit ends, in ms
|
* Time until this rate limit ends, in milliseconds
|
||||||
* @type {number}
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
|
|||||||
@@ -280,7 +280,7 @@ class RequestHandler {
|
|||||||
/**
|
/**
|
||||||
* @typedef {Object} InvalidRequestWarningData
|
* @typedef {Object} InvalidRequestWarningData
|
||||||
* @property {number} count Number of invalid requests that have been made in the window
|
* @property {number} count Number of invalid requests that have been made in the window
|
||||||
* @property {number} remainingTime Time in ms remaining before the count resets
|
* @property {number} remainingTime Time in milliseconds remaining before the count resets
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -249,14 +249,18 @@ class Shard extends EventEmitter {
|
|||||||
const listener = message => {
|
const listener = message => {
|
||||||
if (message?._fetchProp !== prop) return;
|
if (message?._fetchProp !== prop) return;
|
||||||
child.removeListener('message', listener);
|
child.removeListener('message', listener);
|
||||||
|
this.decrementMaxListeners(child);
|
||||||
this._fetches.delete(prop);
|
this._fetches.delete(prop);
|
||||||
if (!message._error) resolve(message._result);
|
if (!message._error) resolve(message._result);
|
||||||
else reject(Util.makeError(message._error));
|
else reject(Util.makeError(message._error));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.incrementMaxListeners(child);
|
||||||
child.on('message', listener);
|
child.on('message', listener);
|
||||||
|
|
||||||
this.send({ _fetchProp: prop }).catch(err => {
|
this.send({ _fetchProp: prop }).catch(err => {
|
||||||
child.removeListener('message', listener);
|
child.removeListener('message', listener);
|
||||||
|
this.decrementMaxListeners(child);
|
||||||
this._fetches.delete(prop);
|
this._fetches.delete(prop);
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
@@ -288,14 +292,18 @@ class Shard extends EventEmitter {
|
|||||||
const listener = message => {
|
const listener = message => {
|
||||||
if (message?._eval !== _eval) return;
|
if (message?._eval !== _eval) return;
|
||||||
child.removeListener('message', listener);
|
child.removeListener('message', listener);
|
||||||
|
this.decrementMaxListeners(child);
|
||||||
this._evals.delete(_eval);
|
this._evals.delete(_eval);
|
||||||
if (!message._error) resolve(message._result);
|
if (!message._error) resolve(message._result);
|
||||||
else reject(Util.makeError(message._error));
|
else reject(Util.makeError(message._error));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.incrementMaxListeners(child);
|
||||||
child.on('message', listener);
|
child.on('message', listener);
|
||||||
|
|
||||||
this.send({ _eval }).catch(err => {
|
this.send({ _eval }).catch(err => {
|
||||||
child.removeListener('message', listener);
|
child.removeListener('message', listener);
|
||||||
|
this.decrementMaxListeners(child);
|
||||||
this._evals.delete(_eval);
|
this._evals.delete(_eval);
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
@@ -406,6 +414,30 @@ class Shard extends EventEmitter {
|
|||||||
|
|
||||||
if (respawn) this.spawn(timeout).catch(err => this.emit('error', err));
|
if (respawn) this.spawn(timeout).catch(err => this.emit('error', err));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments max listeners by one for a given emitter, if they are not zero.
|
||||||
|
* @param {EventEmitter|process} emitter The emitter that emits the events.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
incrementMaxListeners(emitter) {
|
||||||
|
const maxListeners = emitter.getMaxListeners();
|
||||||
|
if (maxListeners !== 0) {
|
||||||
|
emitter.setMaxListeners(maxListeners + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrements max listeners by one for a given emitter, if they are not zero.
|
||||||
|
* @param {EventEmitter|process} emitter The emitter that emits the events.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
decrementMaxListeners(emitter) {
|
||||||
|
const maxListeners = emitter.getMaxListeners();
|
||||||
|
if (maxListeners !== 0) {
|
||||||
|
emitter.setMaxListeners(maxListeners - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Shard;
|
module.exports = Shard;
|
||||||
|
|||||||
@@ -111,13 +111,16 @@ class ShardClientUtil {
|
|||||||
const listener = message => {
|
const listener = message => {
|
||||||
if (message?._sFetchProp !== prop || message._sFetchPropShard !== shard) return;
|
if (message?._sFetchProp !== prop || message._sFetchPropShard !== shard) return;
|
||||||
parent.removeListener('message', listener);
|
parent.removeListener('message', listener);
|
||||||
|
this.decrementMaxListeners(parent);
|
||||||
if (!message._error) resolve(message._result);
|
if (!message._error) resolve(message._result);
|
||||||
else reject(Util.makeError(message._error));
|
else reject(Util.makeError(message._error));
|
||||||
};
|
};
|
||||||
|
this.incrementMaxListeners(parent);
|
||||||
parent.on('message', listener);
|
parent.on('message', listener);
|
||||||
|
|
||||||
this.send({ _sFetchProp: prop, _sFetchPropShard: shard }).catch(err => {
|
this.send({ _sFetchProp: prop, _sFetchPropShard: shard }).catch(err => {
|
||||||
parent.removeListener('message', listener);
|
parent.removeListener('message', listener);
|
||||||
|
this.decrementMaxListeners(parent);
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -146,13 +149,15 @@ class ShardClientUtil {
|
|||||||
const listener = message => {
|
const listener = message => {
|
||||||
if (message?._sEval !== script || message._sEvalShard !== options.shard) return;
|
if (message?._sEval !== script || message._sEvalShard !== options.shard) return;
|
||||||
parent.removeListener('message', listener);
|
parent.removeListener('message', listener);
|
||||||
|
this.decrementMaxListeners(parent);
|
||||||
if (!message._error) resolve(message._result);
|
if (!message._error) resolve(message._result);
|
||||||
else reject(Util.makeError(message._error));
|
else reject(Util.makeError(message._error));
|
||||||
};
|
};
|
||||||
|
this.incrementMaxListeners(parent);
|
||||||
parent.on('message', listener);
|
parent.on('message', listener);
|
||||||
|
|
||||||
this.send({ _sEval: script, _sEvalShard: options.shard }).catch(err => {
|
this.send({ _sEval: script, _sEvalShard: options.shard }).catch(err => {
|
||||||
parent.removeListener('message', listener);
|
parent.removeListener('message', listener);
|
||||||
|
this.decrementMaxListeners(parent);
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -241,6 +246,30 @@ class ShardClientUtil {
|
|||||||
if (shard < 0) throw new Error('SHARDING_SHARD_MISCALCULATION', shard, guildId, shardCount);
|
if (shard < 0) throw new Error('SHARDING_SHARD_MISCALCULATION', shard, guildId, shardCount);
|
||||||
return shard;
|
return shard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments max listeners by one for a given emitter, if they are not zero.
|
||||||
|
* @param {EventEmitter|process} emitter The emitter that emits the events.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
incrementMaxListeners(emitter) {
|
||||||
|
const maxListeners = emitter.getMaxListeners();
|
||||||
|
if (maxListeners !== 0) {
|
||||||
|
emitter.setMaxListeners(maxListeners + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrements max listeners by one for a given emitter, if they are not zero.
|
||||||
|
* @param {EventEmitter|process} emitter The emitter that emits the events.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
decrementMaxListeners(emitter) {
|
||||||
|
const maxListeners = emitter.getMaxListeners();
|
||||||
|
if (maxListeners !== 0) {
|
||||||
|
emitter.setMaxListeners(maxListeners - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ShardClientUtil;
|
module.exports = ShardClientUtil;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class ShardingManager extends EventEmitter {
|
|||||||
* @property {boolean} [respawn=true] Whether shards should automatically respawn upon exiting
|
* @property {boolean} [respawn=true] Whether shards should automatically respawn upon exiting
|
||||||
* @property {string[]} [shardArgs=[]] Arguments to pass to the shard script when spawning
|
* @property {string[]} [shardArgs=[]] Arguments to pass to the shard script when spawning
|
||||||
* (only available when mode is set to 'process')
|
* (only available when mode is set to 'process')
|
||||||
* @property {string} [execArgv=[]] Arguments to pass to the shard script executable when spawning
|
* @property {string[]} [execArgv=[]] Arguments to pass to the shard script executable when spawning
|
||||||
* (only available when mode is set to 'process')
|
* (only available when mode is set to 'process')
|
||||||
* @property {string} [token] Token to use for automatic shard count and passing to shards
|
* @property {string} [token] Token to use for automatic shard count and passing to shards
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -64,6 +64,16 @@ class AnonymousGuild extends BaseGuild {
|
|||||||
*/
|
*/
|
||||||
this.nsfwLevel = NSFWLevels[data.nsfw_level];
|
this.nsfwLevel = NSFWLevels[data.nsfw_level];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('premium_subscription_count' in data) {
|
||||||
|
/**
|
||||||
|
* The total number of boosts for this server
|
||||||
|
* @type {?number}
|
||||||
|
*/
|
||||||
|
this.premiumSubscriptionCount = data.premium_subscription_count;
|
||||||
|
} else {
|
||||||
|
this.premiumSubscriptionCount ??= null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
const Base = require('./Base');
|
const Base = require('./Base');
|
||||||
const ApplicationCommandPermissionsManager = require('../managers/ApplicationCommandPermissionsManager');
|
const ApplicationCommandPermissionsManager = require('../managers/ApplicationCommandPermissionsManager');
|
||||||
const { ApplicationCommandOptionTypes, ApplicationCommandTypes, ChannelTypes } = require('../util/Constants');
|
const { ApplicationCommandOptionTypes, ApplicationCommandTypes, ChannelTypes } = require('../util/Constants');
|
||||||
|
const Permissions = require('../util/Permissions');
|
||||||
const SnowflakeUtil = require('../util/SnowflakeUtil');
|
const SnowflakeUtil = require('../util/SnowflakeUtil');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -62,6 +63,26 @@ class ApplicationCommand extends Base {
|
|||||||
this.name = data.name;
|
this.name = data.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('name_localizations' in data) {
|
||||||
|
/**
|
||||||
|
* The name localizations for this command
|
||||||
|
* @type {?Object<Locale, string>}
|
||||||
|
*/
|
||||||
|
this.nameLocalizations = data.name_localizations;
|
||||||
|
} else {
|
||||||
|
this.nameLocalizations ??= null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('name_localized' in data) {
|
||||||
|
/**
|
||||||
|
* The localized name for this command
|
||||||
|
* @type {?string}
|
||||||
|
*/
|
||||||
|
this.nameLocalized = data.name_localized;
|
||||||
|
} else {
|
||||||
|
this.nameLocalized ??= null;
|
||||||
|
}
|
||||||
|
|
||||||
if ('description' in data) {
|
if ('description' in data) {
|
||||||
/**
|
/**
|
||||||
* The description of this command
|
* The description of this command
|
||||||
@@ -70,6 +91,26 @@ class ApplicationCommand extends Base {
|
|||||||
this.description = data.description;
|
this.description = data.description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('description_localizations' in data) {
|
||||||
|
/**
|
||||||
|
* The description localizations for this command
|
||||||
|
* @type {?Object<Locale, string>}
|
||||||
|
*/
|
||||||
|
this.descriptionLocalizations = data.description_localizations;
|
||||||
|
} else {
|
||||||
|
this.descriptionLocalizations ??= null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('description_localized' in data) {
|
||||||
|
/**
|
||||||
|
* The localized description for this command
|
||||||
|
* @type {?string}
|
||||||
|
*/
|
||||||
|
this.descriptionLocalized = data.description_localized;
|
||||||
|
} else {
|
||||||
|
this.descriptionLocalized ??= null;
|
||||||
|
}
|
||||||
|
|
||||||
if ('options' in data) {
|
if ('options' in data) {
|
||||||
/**
|
/**
|
||||||
* The options of this command
|
* The options of this command
|
||||||
@@ -80,13 +121,39 @@ class ApplicationCommand extends Base {
|
|||||||
this.options ??= [];
|
this.options ??= [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* eslint-disable max-len */
|
||||||
if ('default_permission' in data) {
|
if ('default_permission' in data) {
|
||||||
/**
|
/**
|
||||||
* Whether the command is enabled by default when the app is added to a guild
|
* Whether the command is enabled by default when the app is added to a guild
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
|
* @deprecated Use {@link ApplicationCommand.defaultMemberPermissions} and {@link ApplicationCommand.dmPermission} instead.
|
||||||
*/
|
*/
|
||||||
this.defaultPermission = data.default_permission;
|
this.defaultPermission = data.default_permission;
|
||||||
}
|
}
|
||||||
|
/* eslint-disable max-len */
|
||||||
|
|
||||||
|
if ('default_member_permissions' in data) {
|
||||||
|
/**
|
||||||
|
* The default bitfield used to determine whether this command be used in a guild
|
||||||
|
* @type {?Readonly<Permissions>}
|
||||||
|
*/
|
||||||
|
this.defaultMemberPermissions = data.default_member_permissions
|
||||||
|
? new Permissions(BigInt(data.default_member_permissions)).freeze()
|
||||||
|
: null;
|
||||||
|
} else {
|
||||||
|
this.defaultMemberPermissions ??= null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('dm_permission' in data) {
|
||||||
|
/**
|
||||||
|
* Whether the command can be used in DMs
|
||||||
|
* <info>This property is always `null` on guild commands</info>
|
||||||
|
* @type {?boolean}
|
||||||
|
*/
|
||||||
|
this.dmPermission = data.dm_permission;
|
||||||
|
} else {
|
||||||
|
this.dmPermission ??= null;
|
||||||
|
}
|
||||||
|
|
||||||
if ('version' in data) {
|
if ('version' in data) {
|
||||||
/**
|
/**
|
||||||
@@ -128,10 +195,15 @@ class ApplicationCommand extends Base {
|
|||||||
* Data for creating or editing an application command.
|
* Data for creating or editing an application command.
|
||||||
* @typedef {Object} ApplicationCommandData
|
* @typedef {Object} ApplicationCommandData
|
||||||
* @property {string} name The name of the command
|
* @property {string} name The name of the command
|
||||||
|
* @property {Object<Locale, string>} [nameLocalizations] The localizations for the command name
|
||||||
* @property {string} description The description of the command
|
* @property {string} description The description of the command
|
||||||
|
* @property {Object<Locale, string>} [descriptionLocalizations] The localizations for the command description
|
||||||
* @property {ApplicationCommandType} [type] The type of the command
|
* @property {ApplicationCommandType} [type] The type of the command
|
||||||
* @property {ApplicationCommandOptionData[]} [options] Options for the command
|
* @property {ApplicationCommandOptionData[]} [options] Options for the command
|
||||||
* @property {boolean} [defaultPermission] Whether the command is enabled by default when the app is added to a guild
|
* @property {boolean} [defaultPermission] Whether the command is enabled by default when the app is added to a guild
|
||||||
|
* @property {?PermissionResolvable} [defaultMemberPermissions] The bitfield used to determine the default permissions
|
||||||
|
* a member needs in order to run the command
|
||||||
|
* @property {boolean} [dmPermission] Whether the command is enabled in DMs
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -143,20 +215,33 @@ class ApplicationCommand extends Base {
|
|||||||
* @typedef {Object} ApplicationCommandOptionData
|
* @typedef {Object} ApplicationCommandOptionData
|
||||||
* @property {ApplicationCommandOptionType|number} type The type of the option
|
* @property {ApplicationCommandOptionType|number} type The type of the option
|
||||||
* @property {string} name The name of the option
|
* @property {string} name The name of the option
|
||||||
|
* @property {Object<Locale, string>} [nameLocalizations] The name localizations for the option
|
||||||
* @property {string} description The description of the option
|
* @property {string} description The description of the option
|
||||||
|
* @property {Object<Locale, string>} [descriptionLocalizations] The description localizations for the option
|
||||||
* @property {boolean} [autocomplete] Whether the option is an autocomplete option
|
* @property {boolean} [autocomplete] Whether the option is an autocomplete option
|
||||||
* @property {boolean} [required] Whether the option is required
|
* @property {boolean} [required] Whether the option is required
|
||||||
* @property {ApplicationCommandOptionChoice[]} [choices] The choices of the option for the user to pick from
|
* @property {ApplicationCommandOptionChoiceData[]} [choices] The choices of the option for the user to pick from
|
||||||
* @property {ApplicationCommandOptionData[]} [options] Additional options if this option is a subcommand (group)
|
* @property {ApplicationCommandOptionData[]} [options] Additional options if this option is a subcommand (group)
|
||||||
* @property {ChannelType[]|number[]} [channelTypes] When the option type is channel,
|
* @property {ChannelType[]|number[]} [channelTypes] When the option type is channel,
|
||||||
* the allowed types of channels that can be selected
|
* the allowed types of channels that can be selected
|
||||||
* @property {number} [minValue] The minimum value for an `INTEGER` or `NUMBER` option
|
* @property {number} [minValue] The minimum value for an `INTEGER` or `NUMBER` option
|
||||||
* @property {number} [maxValue] The maximum value for an `INTEGER` or `NUMBER` option
|
* @property {number} [maxValue] The maximum value for an `INTEGER` or `NUMBER` option
|
||||||
|
* @property {number} [minLength] The minimum length for a `STRING` option
|
||||||
|
* (maximum of `6000`)
|
||||||
|
* @property {number} [maxLength] The maximum length for a `STRING` option
|
||||||
|
* (maximum of `6000`)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ApplicationCommandOptionChoiceData
|
||||||
|
* @property {string} name The name of the choice
|
||||||
|
* @property {Object<Locale, string>} [nameLocalizations] The localized names for this choice
|
||||||
|
* @property {string|number} value The value of the choice
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits this application command.
|
* Edits this application command.
|
||||||
* @param {ApplicationCommandData} data The data to update the command with
|
* @param {Partial<ApplicationCommandData>} data The data to update the command with
|
||||||
* @returns {Promise<ApplicationCommand>}
|
* @returns {Promise<ApplicationCommand>}
|
||||||
* @example
|
* @example
|
||||||
* // Edit the description of this command
|
* // Edit the description of this command
|
||||||
@@ -179,6 +264,23 @@ class ApplicationCommand extends Base {
|
|||||||
return this.edit({ name });
|
return this.edit({ name });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edits the localized names of this ApplicationCommand
|
||||||
|
* @param {Object<Locale, string>} nameLocalizations The new localized names for the command
|
||||||
|
* @returns {Promise<ApplicationCommand>}
|
||||||
|
* @example
|
||||||
|
* // Edit the name localizations of this command
|
||||||
|
* command.setLocalizedNames({
|
||||||
|
* 'en-GB': 'test',
|
||||||
|
* 'pt-BR': 'teste',
|
||||||
|
* })
|
||||||
|
* .then(console.log)
|
||||||
|
* .catch(console.error)
|
||||||
|
*/
|
||||||
|
setNameLocalizations(nameLocalizations) {
|
||||||
|
return this.edit({ nameLocalizations });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits the description of this ApplicationCommand
|
* Edits the description of this ApplicationCommand
|
||||||
* @param {string} description The new description of the command
|
* @param {string} description The new description of the command
|
||||||
@@ -188,14 +290,52 @@ class ApplicationCommand extends Base {
|
|||||||
return this.edit({ description });
|
return this.edit({ description });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edits the localized descriptions of this ApplicationCommand
|
||||||
|
* @param {Object<Locale, string>} descriptionLocalizations The new localized descriptions for the command
|
||||||
|
* @returns {Promise<ApplicationCommand>}
|
||||||
|
* @example
|
||||||
|
* // Edit the description localizations of this command
|
||||||
|
* command.setLocalizedDescriptions({
|
||||||
|
* 'en-GB': 'A test command',
|
||||||
|
* 'pt-BR': 'Um comando de teste',
|
||||||
|
* })
|
||||||
|
* .then(console.log)
|
||||||
|
* .catch(console.error)
|
||||||
|
*/
|
||||||
|
setDescriptionLocalizations(descriptionLocalizations) {
|
||||||
|
return this.edit({ descriptionLocalizations });
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eslint-disable max-len */
|
||||||
/**
|
/**
|
||||||
* Edits the default permission of this ApplicationCommand
|
* Edits the default permission of this ApplicationCommand
|
||||||
* @param {boolean} [defaultPermission=true] The default permission for this command
|
* @param {boolean} [defaultPermission=true] The default permission for this command
|
||||||
* @returns {Promise<ApplicationCommand>}
|
* @returns {Promise<ApplicationCommand>}
|
||||||
|
* @deprecated Use {@link ApplicationCommand#setDefaultMemberPermissions} and {@link ApplicationCommand#setDMPermission} instead.
|
||||||
*/
|
*/
|
||||||
setDefaultPermission(defaultPermission = true) {
|
setDefaultPermission(defaultPermission = true) {
|
||||||
return this.edit({ defaultPermission });
|
return this.edit({ defaultPermission });
|
||||||
}
|
}
|
||||||
|
/* eslint-enable max-len */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edits the default member permissions of this ApplicationCommand
|
||||||
|
* @param {?PermissionResolvable} defaultMemberPermissions The default member permissions required to run this command
|
||||||
|
* @returns {Promise<ApplicationCommand>}
|
||||||
|
*/
|
||||||
|
setDefaultMemberPermissions(defaultMemberPermissions) {
|
||||||
|
return this.edit({ defaultMemberPermissions });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edits the DM permission of this ApplicationCommand
|
||||||
|
* @param {boolean} [dmPermission=true] Whether the command can be used in DMs
|
||||||
|
* @returns {Promise<ApplicationCommand>}
|
||||||
|
*/
|
||||||
|
setDMPermission(dmPermission = true) {
|
||||||
|
return this.edit({ dmPermission });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits the options of this ApplicationCommand
|
* Edits the options of this ApplicationCommand
|
||||||
@@ -232,6 +372,20 @@ class ApplicationCommand extends Base {
|
|||||||
// If given an id, check if the id matches
|
// If given an id, check if the id matches
|
||||||
if (command.id && this.id !== command.id) return false;
|
if (command.id && this.id !== command.id) return false;
|
||||||
|
|
||||||
|
let defaultMemberPermissions = null;
|
||||||
|
let dmPermission = command.dmPermission ?? command.dm_permission;
|
||||||
|
|
||||||
|
if ('default_member_permissions' in command) {
|
||||||
|
defaultMemberPermissions = command.default_member_permissions
|
||||||
|
? new Permissions(BigInt(command.default_member_permissions)).bitfield
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('defaultMemberPermissions' in command) {
|
||||||
|
defaultMemberPermissions =
|
||||||
|
command.defaultMemberPermissions !== null ? new Permissions(command.defaultMemberPermissions).bitfield : null;
|
||||||
|
}
|
||||||
|
|
||||||
// Check top level parameters
|
// Check top level parameters
|
||||||
const commandType = typeof command.type === 'string' ? command.type : ApplicationCommandTypes[command.type];
|
const commandType = typeof command.type === 'string' ? command.type : ApplicationCommandTypes[command.type];
|
||||||
if (
|
if (
|
||||||
@@ -240,6 +394,8 @@ class ApplicationCommand extends Base {
|
|||||||
('version' in command && command.version !== this.version) ||
|
('version' in command && command.version !== this.version) ||
|
||||||
('autocomplete' in command && command.autocomplete !== this.autocomplete) ||
|
('autocomplete' in command && command.autocomplete !== this.autocomplete) ||
|
||||||
(commandType && commandType !== this.type) ||
|
(commandType && commandType !== this.type) ||
|
||||||
|
defaultMemberPermissions !== (this.defaultMemberPermissions?.bitfield ?? null) ||
|
||||||
|
(typeof dmPermission !== 'undefined' && dmPermission !== this.dmPermission) ||
|
||||||
// Future proof for options being nullable
|
// Future proof for options being nullable
|
||||||
// TODO: remove ?? 0 on each when nullable
|
// TODO: remove ?? 0 on each when nullable
|
||||||
(command.options?.length ?? 0) !== (this.options?.length ?? 0) ||
|
(command.options?.length ?? 0) !== (this.options?.length ?? 0) ||
|
||||||
@@ -301,7 +457,9 @@ class ApplicationCommand extends Base {
|
|||||||
option.options?.length !== existing.options?.length ||
|
option.options?.length !== existing.options?.length ||
|
||||||
(option.channelTypes ?? option.channel_types)?.length !== existing.channelTypes?.length ||
|
(option.channelTypes ?? option.channel_types)?.length !== existing.channelTypes?.length ||
|
||||||
(option.minValue ?? option.min_value) !== existing.minValue ||
|
(option.minValue ?? option.min_value) !== existing.minValue ||
|
||||||
(option.maxValue ?? option.max_value) !== existing.maxValue
|
(option.maxValue ?? option.max_value) !== existing.maxValue ||
|
||||||
|
(option.minLength ?? option.min_length) !== existing.minLength ||
|
||||||
|
(option.maxLength ?? option.max_length) !== existing.maxLength
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -344,7 +502,11 @@ class ApplicationCommand extends Base {
|
|||||||
* @typedef {Object} ApplicationCommandOption
|
* @typedef {Object} ApplicationCommandOption
|
||||||
* @property {ApplicationCommandOptionType} type The type of the option
|
* @property {ApplicationCommandOptionType} type The type of the option
|
||||||
* @property {string} name The name of the option
|
* @property {string} name The name of the option
|
||||||
|
* @property {Object<string, string>} [nameLocalizations] The localizations for the option name
|
||||||
|
* @property {string} [nameLocalized] The localized name for this option
|
||||||
* @property {string} description The description of the option
|
* @property {string} description The description of the option
|
||||||
|
* @property {Object<string, string>} [descriptionLocalizations] The localizations for the option description
|
||||||
|
* @property {string} [descriptionLocalized] The localized description for this option
|
||||||
* @property {boolean} [required] Whether the option is required
|
* @property {boolean} [required] Whether the option is required
|
||||||
* @property {boolean} [autocomplete] Whether the option is an autocomplete option
|
* @property {boolean} [autocomplete] Whether the option is an autocomplete option
|
||||||
* @property {ApplicationCommandOptionChoice[]} [choices] The choices of the option for the user to pick from
|
* @property {ApplicationCommandOptionChoice[]} [choices] The choices of the option for the user to pick from
|
||||||
@@ -353,18 +515,24 @@ class ApplicationCommand extends Base {
|
|||||||
* the allowed types of channels that can be selected
|
* the allowed types of channels that can be selected
|
||||||
* @property {number} [minValue] The minimum value for an `INTEGER` or `NUMBER` option
|
* @property {number} [minValue] The minimum value for an `INTEGER` or `NUMBER` option
|
||||||
* @property {number} [maxValue] The maximum value for an `INTEGER` or `NUMBER` option
|
* @property {number} [maxValue] The maximum value for an `INTEGER` or `NUMBER` option
|
||||||
|
* @property {number} [minLength] The minimum length for a `STRING` option
|
||||||
|
* (maximum of `6000`)
|
||||||
|
* @property {number} [maxLength] The maximum length for a `STRING` option
|
||||||
|
* (maximum of `6000`)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A choice for an application command option.
|
* A choice for an application command option.
|
||||||
* @typedef {Object} ApplicationCommandOptionChoice
|
* @typedef {Object} ApplicationCommandOptionChoice
|
||||||
* @property {string} name The name of the choice
|
* @property {string} name The name of the choice
|
||||||
|
* @property {?string} nameLocalized The localized name of the choice in the provided locale, if any
|
||||||
|
* @property {?Object<string, string>} [nameLocalizations] The localized names for this choice
|
||||||
* @property {string|number} value The value of the choice
|
* @property {string|number} value The value of the choice
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms an {@link ApplicationCommandOptionData} object into something that can be used with the API.
|
* Transforms an {@link ApplicationCommandOptionData} object into something that can be used with the API.
|
||||||
* @param {ApplicationCommandOptionData} option The option to transform
|
* @param {ApplicationCommandOptionData|ApplicationCommandOption} option The option to transform
|
||||||
* @param {boolean} [received] Whether this option has been received from Discord
|
* @param {boolean} [received] Whether this option has been received from Discord
|
||||||
* @returns {APIApplicationCommandOption}
|
* @returns {APIApplicationCommandOption}
|
||||||
* @private
|
* @private
|
||||||
@@ -374,14 +542,29 @@ class ApplicationCommand extends Base {
|
|||||||
const channelTypesKey = received ? 'channelTypes' : 'channel_types';
|
const channelTypesKey = received ? 'channelTypes' : 'channel_types';
|
||||||
const minValueKey = received ? 'minValue' : 'min_value';
|
const minValueKey = received ? 'minValue' : 'min_value';
|
||||||
const maxValueKey = received ? 'maxValue' : 'max_value';
|
const maxValueKey = received ? 'maxValue' : 'max_value';
|
||||||
|
const minLengthKey = received ? 'minLength' : 'min_length';
|
||||||
|
const maxLengthKey = received ? 'maxLength' : 'max_length';
|
||||||
|
const nameLocalizationsKey = received ? 'nameLocalizations' : 'name_localizations';
|
||||||
|
const nameLocalizedKey = received ? 'nameLocalized' : 'name_localized';
|
||||||
|
const descriptionLocalizationsKey = received ? 'descriptionLocalizations' : 'description_localizations';
|
||||||
|
const descriptionLocalizedKey = received ? 'descriptionLocalized' : 'description_localized';
|
||||||
return {
|
return {
|
||||||
type: typeof option.type === 'number' && !received ? option.type : ApplicationCommandOptionTypes[option.type],
|
type: typeof option.type === 'number' && !received ? option.type : ApplicationCommandOptionTypes[option.type],
|
||||||
name: option.name,
|
name: option.name,
|
||||||
|
[nameLocalizationsKey]: option.nameLocalizations ?? option.name_localizations,
|
||||||
|
[nameLocalizedKey]: option.nameLocalized ?? option.name_localized,
|
||||||
description: option.description,
|
description: option.description,
|
||||||
|
[descriptionLocalizationsKey]: option.descriptionLocalizations ?? option.description_localizations,
|
||||||
|
[descriptionLocalizedKey]: option.descriptionLocalized ?? option.description_localized,
|
||||||
required:
|
required:
|
||||||
option.required ?? (stringType === 'SUB_COMMAND' || stringType === 'SUB_COMMAND_GROUP' ? undefined : false),
|
option.required ?? (stringType === 'SUB_COMMAND' || stringType === 'SUB_COMMAND_GROUP' ? undefined : false),
|
||||||
autocomplete: option.autocomplete,
|
autocomplete: option.autocomplete,
|
||||||
choices: option.choices,
|
choices: option.choices?.map(choice => ({
|
||||||
|
name: choice.name,
|
||||||
|
[nameLocalizedKey]: choice.nameLocalized ?? choice.name_localized,
|
||||||
|
[nameLocalizationsKey]: choice.nameLocalizations ?? choice.name_localizations,
|
||||||
|
value: choice.value,
|
||||||
|
})),
|
||||||
options: option.options?.map(o => this.transformOption(o, received)),
|
options: option.options?.map(o => this.transformOption(o, received)),
|
||||||
[channelTypesKey]: received
|
[channelTypesKey]: received
|
||||||
? option.channel_types?.map(type => ChannelTypes[type])
|
? option.channel_types?.map(type => ChannelTypes[type])
|
||||||
@@ -390,6 +573,8 @@ class ApplicationCommand extends Base {
|
|||||||
option.channel_types,
|
option.channel_types,
|
||||||
[minValueKey]: option.minValue ?? option.min_value,
|
[minValueKey]: option.minValue ?? option.min_value,
|
||||||
[maxValueKey]: option.maxValue ?? option.max_value,
|
[maxValueKey]: option.maxValue ?? option.max_value,
|
||||||
|
[minLengthKey]: option.minLength ?? option.min_length,
|
||||||
|
[maxLengthKey]: option.maxLength ?? option.max_length,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class AutocompleteInteraction extends Interaction {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends results for the autocomplete of this interaction.
|
* Sends results for the autocomplete of this interaction.
|
||||||
* @param {ApplicationCommandOptionChoice[]} options The options for the autocomplete
|
* @param {ApplicationCommandOptionChoiceData[]} options The options for the autocomplete
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
* @example
|
* @example
|
||||||
* // respond to autocomplete interaction
|
* // respond to autocomplete interaction
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
const { Collection } = require('@discordjs/collection');
|
const { Collection } = require('@discordjs/collection');
|
||||||
const Interaction = require('./Interaction');
|
const Interaction = require('./Interaction');
|
||||||
const InteractionWebhook = require('./InteractionWebhook');
|
const InteractionWebhook = require('./InteractionWebhook');
|
||||||
|
const MessageAttachment = require('./MessageAttachment');
|
||||||
const InteractionResponses = require('./interfaces/InteractionResponses');
|
const InteractionResponses = require('./interfaces/InteractionResponses');
|
||||||
const { ApplicationCommandOptionTypes } = require('../util/Constants');
|
const { ApplicationCommandOptionTypes } = require('../util/Constants');
|
||||||
|
|
||||||
@@ -76,6 +77,7 @@ class BaseCommandInteraction extends Interaction {
|
|||||||
* @property {Collection<Snowflake, Role|APIRole>} [roles] The resolved roles
|
* @property {Collection<Snowflake, Role|APIRole>} [roles] The resolved roles
|
||||||
* @property {Collection<Snowflake, Channel|APIChannel>} [channels] The resolved channels
|
* @property {Collection<Snowflake, Channel|APIChannel>} [channels] The resolved channels
|
||||||
* @property {Collection<Snowflake, Message|APIMessage>} [messages] The resolved messages
|
* @property {Collection<Snowflake, Message|APIMessage>} [messages] The resolved messages
|
||||||
|
* @property {Collection<Snowflake, MessageAttachment>} [attachments] The resolved attachments
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,7 +86,7 @@ class BaseCommandInteraction extends Interaction {
|
|||||||
* @returns {CommandInteractionResolvedData}
|
* @returns {CommandInteractionResolvedData}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
transformResolved({ members, users, channels, roles, messages }) {
|
transformResolved({ members, users, channels, roles, messages, attachments }) {
|
||||||
const result = {};
|
const result = {};
|
||||||
|
|
||||||
if (members) {
|
if (members) {
|
||||||
@@ -123,6 +125,14 @@ class BaseCommandInteraction extends Interaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (attachments) {
|
||||||
|
result.attachments = new Collection();
|
||||||
|
for (const attachment of Object.values(attachments)) {
|
||||||
|
const patched = new MessageAttachment(attachment.url, attachment.filename, attachment);
|
||||||
|
result.attachments.set(attachment.id, patched);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,6 +149,7 @@ class BaseCommandInteraction extends Interaction {
|
|||||||
* @property {GuildMember|APIGuildMember} [member] The resolved member
|
* @property {GuildMember|APIGuildMember} [member] The resolved member
|
||||||
* @property {GuildChannel|ThreadChannel|APIChannel} [channel] The resolved channel
|
* @property {GuildChannel|ThreadChannel|APIChannel} [channel] The resolved channel
|
||||||
* @property {Role|APIRole} [role] The resolved role
|
* @property {Role|APIRole} [role] The resolved role
|
||||||
|
* @property {MessageAttachment} [attachment] The resolved attachment
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -169,6 +180,9 @@ class BaseCommandInteraction extends Interaction {
|
|||||||
|
|
||||||
const role = resolved.roles?.[option.value];
|
const role = resolved.roles?.[option.value];
|
||||||
if (role) result.role = this.guild?.roles._add(role) ?? role;
|
if (role) result.role = this.guild?.roles._add(role) ?? role;
|
||||||
|
|
||||||
|
const attachment = resolved.attachments?.[option.value];
|
||||||
|
if (attachment) result.attachment = new MessageAttachment(attachment.url, attachment.filename, attachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -182,6 +196,8 @@ class BaseCommandInteraction extends Interaction {
|
|||||||
editReply() {}
|
editReply() {}
|
||||||
deleteReply() {}
|
deleteReply() {}
|
||||||
followUp() {}
|
followUp() {}
|
||||||
|
showModal() {}
|
||||||
|
awaitModalSubmit() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
InteractionResponses.applyToClass(BaseCommandInteraction, ['deferUpdate', 'update']);
|
InteractionResponses.applyToClass(BaseCommandInteraction, ['deferUpdate', 'update']);
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { Collection } = require('@discordjs/collection');
|
|
||||||
const GuildChannel = require('./GuildChannel');
|
const GuildChannel = require('./GuildChannel');
|
||||||
const Webhook = require('./Webhook');
|
|
||||||
const TextBasedChannel = require('./interfaces/TextBasedChannel');
|
const TextBasedChannel = require('./interfaces/TextBasedChannel');
|
||||||
const MessageManager = require('../managers/MessageManager');
|
const MessageManager = require('../managers/MessageManager');
|
||||||
const ThreadManager = require('../managers/ThreadManager');
|
const ThreadManager = require('../managers/ThreadManager');
|
||||||
const DataResolver = require('../util/DataResolver');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a text-based guild channel on Discord.
|
* Represents a text-based guild channel on Discord.
|
||||||
@@ -72,7 +69,7 @@ class BaseGuildTextChannel extends GuildChannel {
|
|||||||
if ('default_auto_archive_duration' in data) {
|
if ('default_auto_archive_duration' in data) {
|
||||||
/**
|
/**
|
||||||
* The default auto archive duration for newly created threads in this channel
|
* The default auto archive duration for newly created threads in this channel
|
||||||
* @type {?ThreadAutoArchiveDuration}
|
* @type {?number}
|
||||||
*/
|
*/
|
||||||
this.defaultAutoArchiveDuration = data.default_auto_archive_duration;
|
this.defaultAutoArchiveDuration = data.default_auto_archive_duration;
|
||||||
}
|
}
|
||||||
@@ -92,16 +89,6 @@ class BaseGuildTextChannel extends GuildChannel {
|
|||||||
return this.edit({ defaultAutoArchiveDuration }, reason);
|
return this.edit({ defaultAutoArchiveDuration }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets whether this channel is flagged as NSFW.
|
|
||||||
* @param {boolean} [nsfw=true] Whether the channel should be considered NSFW
|
|
||||||
* @param {string} [reason] Reason for changing the channel's NSFW flag
|
|
||||||
* @returns {Promise<TextChannel>}
|
|
||||||
*/
|
|
||||||
setNSFW(nsfw = true, reason) {
|
|
||||||
return this.edit({ nsfw }, reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the type of this channel (only conversion between text and news is supported)
|
* Sets the type of this channel (only conversion between text and news is supported)
|
||||||
* @param {string} type The new channel type
|
* @param {string} type The new channel type
|
||||||
@@ -112,57 +99,6 @@ class BaseGuildTextChannel extends GuildChannel {
|
|||||||
return this.edit({ type }, reason);
|
return this.edit({ type }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches all webhooks for the channel.
|
|
||||||
* @returns {Promise<Collection<Snowflake, Webhook>>}
|
|
||||||
* @example
|
|
||||||
* // Fetch webhooks
|
|
||||||
* channel.fetchWebhooks()
|
|
||||||
* .then(hooks => console.log(`This channel has ${hooks.size} hooks`))
|
|
||||||
* .catch(console.error);
|
|
||||||
*/
|
|
||||||
async fetchWebhooks() {
|
|
||||||
const data = await this.client.api.channels[this.id].webhooks.get();
|
|
||||||
const hooks = new Collection();
|
|
||||||
for (const hook of data) hooks.set(hook.id, new Webhook(this.client, hook));
|
|
||||||
return hooks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Options used to create a {@link Webhook} in a {@link TextChannel} or a {@link NewsChannel}.
|
|
||||||
* @typedef {Object} ChannelWebhookCreateOptions
|
|
||||||
* @property {?(BufferResolvable|Base64Resolvable)} [avatar] Avatar for the webhook
|
|
||||||
* @property {string} [reason] Reason for creating the webhook
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a webhook for the channel.
|
|
||||||
* @param {string} name The name of the webhook
|
|
||||||
* @param {ChannelWebhookCreateOptions} [options] Options for creating the webhook
|
|
||||||
* @returns {Promise<Webhook>} Returns the created Webhook
|
|
||||||
* @example
|
|
||||||
* // Create a webhook for the current channel
|
|
||||||
* channel.createWebhook('Snek', {
|
|
||||||
* avatar: 'https://i.imgur.com/mI8XcpG.jpg',
|
|
||||||
* reason: 'Needed a cool new Webhook'
|
|
||||||
* })
|
|
||||||
* .then(console.log)
|
|
||||||
* .catch(console.error)
|
|
||||||
*/
|
|
||||||
async createWebhook(name, { avatar, reason } = {}) {
|
|
||||||
if (typeof avatar === 'string' && !avatar.startsWith('data:')) {
|
|
||||||
avatar = await DataResolver.resolveImage(avatar);
|
|
||||||
}
|
|
||||||
const data = await this.client.api.channels[this.id].webhooks.post({
|
|
||||||
data: {
|
|
||||||
name,
|
|
||||||
avatar,
|
|
||||||
},
|
|
||||||
reason,
|
|
||||||
});
|
|
||||||
return new Webhook(this.client, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a new topic for the guild channel.
|
* Sets a new topic for the guild channel.
|
||||||
* @param {?string} topic The new topic for the guild channel
|
* @param {?string} topic The new topic for the guild channel
|
||||||
@@ -178,6 +114,14 @@ class BaseGuildTextChannel extends GuildChannel {
|
|||||||
return this.edit({ topic }, reason);
|
return this.edit({ topic }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data that can be resolved to an Application. This can be:
|
||||||
|
* * An Application
|
||||||
|
* * An Activity with associated Application
|
||||||
|
* * A Snowflake
|
||||||
|
* @typedef {Application|Snowflake} ApplicationResolvable
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options used to create an invite to a guild channel.
|
* Options used to create an invite to a guild channel.
|
||||||
* @typedef {Object} CreateInviteOptions
|
* @typedef {Object} CreateInviteOptions
|
||||||
@@ -229,6 +173,10 @@ class BaseGuildTextChannel extends GuildChannel {
|
|||||||
createMessageComponentCollector() {}
|
createMessageComponentCollector() {}
|
||||||
awaitMessageComponent() {}
|
awaitMessageComponent() {}
|
||||||
bulkDelete() {}
|
bulkDelete() {}
|
||||||
|
fetchWebhooks() {}
|
||||||
|
createWebhook() {}
|
||||||
|
setRateLimitPerUser() {}
|
||||||
|
setNSFW() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextBasedChannel.applyToClass(BaseGuildTextChannel, true);
|
TextBasedChannel.applyToClass(BaseGuildTextChannel, true);
|
||||||
|
|||||||
@@ -82,17 +82,18 @@ class BaseGuildVoiceChannel extends GuildChannel {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the RTC region of the channel.
|
* Sets the RTC region of the channel.
|
||||||
* @param {?string} region The new region of the channel. Set to `null` to remove a specific region for the channel
|
* @param {?string} rtcRegion The new region of the channel. Set to `null` to remove a specific region for the channel
|
||||||
|
* @param {string} [reason] The reason for modifying this region.
|
||||||
* @returns {Promise<BaseGuildVoiceChannel>}
|
* @returns {Promise<BaseGuildVoiceChannel>}
|
||||||
* @example
|
* @example
|
||||||
* // Set the RTC region to europe
|
* // Set the RTC region to sydney
|
||||||
* channel.setRTCRegion('europe');
|
* channel.setRTCRegion('sydney');
|
||||||
* @example
|
* @example
|
||||||
* // Remove a fixed region for this channel - let Discord decide automatically
|
* // Remove a fixed region for this channel - let Discord decide automatically
|
||||||
* channel.setRTCRegion(null);
|
* channel.setRTCRegion(null, 'We want to let Discord decide.');
|
||||||
*/
|
*/
|
||||||
setRTCRegion(region) {
|
setRTCRegion(rtcRegion, reason) {
|
||||||
return this.edit({ rtcRegion: region });
|
return this.edit({ rtcRegion }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const { TypeError } = require('../errors');
|
|||||||
const { MessageComponentTypes, Events } = require('../util/Constants');
|
const { MessageComponentTypes, Events } = require('../util/Constants');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an interactive component of a Message. It should not be necessary to construct this directly.
|
* Represents an interactive component of a Message or Modal. It should not be necessary to construct this directly.
|
||||||
* See {@link MessageComponent}
|
* See {@link MessageComponent}
|
||||||
*/
|
*/
|
||||||
class BaseMessageComponent {
|
class BaseMessageComponent {
|
||||||
@@ -15,18 +15,20 @@ class BaseMessageComponent {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data that can be resolved into options for a MessageComponent. This can be:
|
* Data that can be resolved into options for a component. This can be:
|
||||||
* * MessageActionRowOptions
|
* * MessageActionRowOptions
|
||||||
* * MessageButtonOptions
|
* * MessageButtonOptions
|
||||||
* * MessageSelectMenuOptions
|
* * MessageSelectMenuOptions
|
||||||
|
* * TextInputComponentOptions
|
||||||
* @typedef {MessageActionRowOptions|MessageButtonOptions|MessageSelectMenuOptions} MessageComponentOptions
|
* @typedef {MessageActionRowOptions|MessageButtonOptions|MessageSelectMenuOptions} MessageComponentOptions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Components that can be sent in a message. These can be:
|
* Components that can be sent in a payload. These can be:
|
||||||
* * MessageActionRow
|
* * MessageActionRow
|
||||||
* * MessageButton
|
* * MessageButton
|
||||||
* * MessageSelectMenu
|
* * MessageSelectMenu
|
||||||
|
* * TextInputComponent
|
||||||
* @typedef {MessageActionRow|MessageButton|MessageSelectMenu} MessageComponent
|
* @typedef {MessageActionRow|MessageButton|MessageSelectMenu} MessageComponent
|
||||||
* @see {@link https://discord.com/developers/docs/interactions/message-components#component-object-component-types}
|
* @see {@link https://discord.com/developers/docs/interactions/message-components#component-object-component-types}
|
||||||
*/
|
*/
|
||||||
@@ -51,10 +53,10 @@ class BaseMessageComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a MessageComponent based on the type of the incoming data
|
* Constructs a component based on the type of the incoming data
|
||||||
* @param {MessageComponentOptions} data Data for a MessageComponent
|
* @param {MessageComponentOptions} data Data for a MessageComponent
|
||||||
* @param {Client|WebhookClient} [client] Client constructing this component
|
* @param {Client|WebhookClient} [client] Client constructing this component
|
||||||
* @returns {?MessageComponent}
|
* @returns {?(MessageComponent|ModalComponent)}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
static create(data, client) {
|
static create(data, client) {
|
||||||
@@ -79,6 +81,11 @@ class BaseMessageComponent {
|
|||||||
component = data instanceof MessageSelectMenu ? data : new MessageSelectMenu(data);
|
component = data instanceof MessageSelectMenu ? data : new MessageSelectMenu(data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case MessageComponentTypes.TEXT_INPUT: {
|
||||||
|
const TextInputComponent = require('./TextInputComponent');
|
||||||
|
component = data instanceof TextInputComponent ? data : new TextInputComponent(data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
if (client) {
|
if (client) {
|
||||||
client.emit(Events.DEBUG, `[BaseMessageComponent] Received component with unknown type: ${data.type}`);
|
client.emit(Events.DEBUG, `[BaseMessageComponent] Received component with unknown type: ${data.type}`);
|
||||||
@@ -90,7 +97,7 @@ class BaseMessageComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves the type of a MessageComponent
|
* Resolves the type of a component
|
||||||
* @param {MessageComponentTypeResolvable} type The type to resolve
|
* @param {MessageComponentTypeResolvable} type The type to resolve
|
||||||
* @returns {MessageComponentType}
|
* @returns {MessageComponentType}
|
||||||
* @private
|
* @private
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ let StoreChannel;
|
|||||||
let TextChannel;
|
let TextChannel;
|
||||||
let ThreadChannel;
|
let ThreadChannel;
|
||||||
let VoiceChannel;
|
let VoiceChannel;
|
||||||
|
let DirectoryChannel;
|
||||||
const { ChannelTypes, ThreadChannelTypes, VoiceBasedChannelTypes } = require('../util/Constants');
|
const { ChannelTypes, ThreadChannelTypes, VoiceBasedChannelTypes } = require('../util/Constants');
|
||||||
const SnowflakeUtil = require('../util/SnowflakeUtil');
|
const SnowflakeUtil = require('../util/SnowflakeUtil');
|
||||||
|
|
||||||
@@ -164,6 +165,14 @@ class Channel extends Base {
|
|||||||
return ThreadChannelTypes.includes(this.type);
|
return ThreadChannelTypes.includes(this.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether this channel is a {@link DirectoryChannel}
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
isDirectory() {
|
||||||
|
return this.type === 'GUILD_DIRECTORY';
|
||||||
|
}
|
||||||
|
|
||||||
static create(client, data, guild, { allowUnknownGuild, fromInteraction } = {}) {
|
static create(client, data, guild, { allowUnknownGuild, fromInteraction } = {}) {
|
||||||
CategoryChannel ??= require('./CategoryChannel');
|
CategoryChannel ??= require('./CategoryChannel');
|
||||||
DMChannel ??= require('./DMChannel');
|
DMChannel ??= require('./DMChannel');
|
||||||
@@ -173,6 +182,7 @@ class Channel extends Base {
|
|||||||
TextChannel ??= require('./TextChannel');
|
TextChannel ??= require('./TextChannel');
|
||||||
ThreadChannel ??= require('./ThreadChannel');
|
ThreadChannel ??= require('./ThreadChannel');
|
||||||
VoiceChannel ??= require('./VoiceChannel');
|
VoiceChannel ??= require('./VoiceChannel');
|
||||||
|
DirectoryChannel ??= require('./DirectoryChannel');
|
||||||
|
|
||||||
let channel;
|
let channel;
|
||||||
if (!data.guild_id && !guild) {
|
if (!data.guild_id && !guild) {
|
||||||
@@ -218,6 +228,10 @@ class Channel extends Base {
|
|||||||
if (!allowUnknownGuild) channel.parent?.threads.cache.set(channel.id, channel);
|
if (!allowUnknownGuild) channel.parent?.threads.cache.set(channel.id, channel);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ChannelTypes.GUILD_DIRECTORY:
|
||||||
|
channel = new DirectoryChannel(client, data);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (channel && !allowUnknownGuild) guild.channels?.cache.set(channel.id, channel);
|
if (channel && !allowUnknownGuild) guild.channels?.cache.set(channel.id, channel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,13 @@ const Team = require('./Team');
|
|||||||
const Application = require('./interfaces/Application');
|
const Application = require('./interfaces/Application');
|
||||||
const ApplicationCommandManager = require('../managers/ApplicationCommandManager');
|
const ApplicationCommandManager = require('../managers/ApplicationCommandManager');
|
||||||
const ApplicationFlags = require('../util/ApplicationFlags');
|
const ApplicationFlags = require('../util/ApplicationFlags');
|
||||||
|
const Permissions = require('../util/Permissions');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ClientApplicationInstallParams
|
||||||
|
* @property {InviteScope[]} scopes The scopes to add the application to the server with
|
||||||
|
* @property {Readonly<Permissions>} permissions The permissions this bot will request upon joining
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a Client OAuth2 Application.
|
* Represents a Client OAuth2 Application.
|
||||||
@@ -23,6 +30,35 @@ class ClientApplication extends Application {
|
|||||||
_patch(data) {
|
_patch(data) {
|
||||||
super._patch(data);
|
super._patch(data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The tags this application has (max of 5)
|
||||||
|
* @type {string[]}
|
||||||
|
*/
|
||||||
|
this.tags = data.tags ?? [];
|
||||||
|
|
||||||
|
if ('install_params' in data) {
|
||||||
|
/**
|
||||||
|
* Settings for this application's default in-app authorization
|
||||||
|
* @type {?ClientApplicationInstallParams}
|
||||||
|
*/
|
||||||
|
this.installParams = {
|
||||||
|
scopes: data.install_params.scopes,
|
||||||
|
permissions: new Permissions(data.install_params.permissions).freeze(),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
this.installParams ??= null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('custom_install_url' in data) {
|
||||||
|
/**
|
||||||
|
* This application's custom installation URL
|
||||||
|
* @type {?string}
|
||||||
|
*/
|
||||||
|
this.customInstallURL = data.custom_install_url;
|
||||||
|
} else {
|
||||||
|
this.customInstallURL = null;
|
||||||
|
}
|
||||||
|
|
||||||
if ('flags' in data) {
|
if ('flags' in data) {
|
||||||
/**
|
/**
|
||||||
* The flags this application has
|
* The flags this application has
|
||||||
|
|||||||
@@ -240,10 +240,19 @@ class CommandInteractionOptionResolver {
|
|||||||
return option?.message ?? null;
|
return option?.message ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The full autocomplete option object.
|
||||||
|
* @typedef {Object} AutocompleteFocusedOption
|
||||||
|
* @property {string} name The name of the option
|
||||||
|
* @property {ApplicationCommandOptionType} type The type of the application command option
|
||||||
|
* @property {string} value The value of the option
|
||||||
|
* @property {boolean} focused Whether this option is currently in focus for autocomplete
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the focused option.
|
* Gets the focused option.
|
||||||
* @param {boolean} [getFull=false] Whether to get the full option object
|
* @param {boolean} [getFull=false] Whether to get the full option object
|
||||||
* @returns {string|number|ApplicationCommandOptionChoice}
|
* @returns {string|AutocompleteFocusedOption}
|
||||||
* The value of the option, or the whole option if getFull is true
|
* The value of the option, or the whole option if getFull is true
|
||||||
*/
|
*/
|
||||||
getFocused(getFull = false) {
|
getFocused(getFull = false) {
|
||||||
@@ -251,6 +260,17 @@ class CommandInteractionOptionResolver {
|
|||||||
if (!focusedOption) throw new TypeError('AUTOCOMPLETE_INTERACTION_OPTION_NO_FOCUSED_OPTION');
|
if (!focusedOption) throw new TypeError('AUTOCOMPLETE_INTERACTION_OPTION_NO_FOCUSED_OPTION');
|
||||||
return getFull ? focusedOption : focusedOption.value;
|
return getFull ? focusedOption : focusedOption.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an attachment option.
|
||||||
|
* @param {string} name The name of the option.
|
||||||
|
* @param {boolean} [required=false] Whether to throw an error if the option is not found.
|
||||||
|
* @returns {?MessageAttachment} The value of the option, or null if not set and not required.
|
||||||
|
*/
|
||||||
|
getAttachment(name, required = false) {
|
||||||
|
const option = this._getTypedOption(name, 'ATTACHMENT', ['attachment'], required);
|
||||||
|
return option?.attachment ?? null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = CommandInteractionOptionResolver;
|
module.exports = CommandInteractionOptionResolver;
|
||||||
|
|||||||
@@ -94,8 +94,16 @@ class DMChannel extends Channel {
|
|||||||
createMessageComponentCollector() {}
|
createMessageComponentCollector() {}
|
||||||
awaitMessageComponent() {}
|
awaitMessageComponent() {}
|
||||||
// Doesn't work on DM channels; bulkDelete() {}
|
// Doesn't work on DM channels; bulkDelete() {}
|
||||||
|
// Doesn't work on DM channels; setRateLimitPerUser() {}
|
||||||
|
// Doesn't work on DM channels; setNSFW() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextBasedChannel.applyToClass(DMChannel, true, ['bulkDelete']);
|
TextBasedChannel.applyToClass(DMChannel, true, [
|
||||||
|
'bulkDelete',
|
||||||
|
'fetchWebhooks',
|
||||||
|
'createWebhook',
|
||||||
|
'setRateLimitPerUser',
|
||||||
|
'setNSFW',
|
||||||
|
]);
|
||||||
|
|
||||||
module.exports = DMChannel;
|
module.exports = DMChannel;
|
||||||
|
|||||||
19
src/structures/DirectoryChannel.js
Normal file
19
src/structures/DirectoryChannel.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { Channel } = require('./Channel');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a channel that displays a directory of guilds
|
||||||
|
*/
|
||||||
|
class DirectoryChannel extends Channel {
|
||||||
|
_patch(data) {
|
||||||
|
super._patch(data);
|
||||||
|
/**
|
||||||
|
* The channel's name
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
this.name = data.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = DirectoryChannel;
|
||||||
@@ -286,14 +286,6 @@ class Guild extends AnonymousGuild {
|
|||||||
this.premiumTier = PremiumTiers[data.premium_tier];
|
this.premiumTier = PremiumTiers[data.premium_tier];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('premium_subscription_count' in data) {
|
|
||||||
/**
|
|
||||||
* The total number of boosts for this server
|
|
||||||
* @type {?number}
|
|
||||||
*/
|
|
||||||
this.premiumSubscriptionCount = data.premium_subscription_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('widget_enabled' in data) {
|
if ('widget_enabled' in data) {
|
||||||
/**
|
/**
|
||||||
* Whether widget images are enabled on this guild
|
* Whether widget images are enabled on this guild
|
||||||
@@ -371,6 +363,16 @@ class Guild extends AnonymousGuild {
|
|||||||
this.maximumPresences ??= null;
|
this.maximumPresences ??= null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('max_video_channel_users' in data) {
|
||||||
|
/**
|
||||||
|
* The maximum amount of users allowed in a video channel.
|
||||||
|
* @type {?number}
|
||||||
|
*/
|
||||||
|
this.maxVideoChannelUsers = data.max_video_channel_users;
|
||||||
|
} else {
|
||||||
|
this.maxVideoChannelUsers ??= null;
|
||||||
|
}
|
||||||
|
|
||||||
if ('approximate_member_count' in data) {
|
if ('approximate_member_count' in data) {
|
||||||
/**
|
/**
|
||||||
* The approximate amount of members the guild has
|
* The approximate amount of members the guild has
|
||||||
@@ -419,8 +421,8 @@ class Guild extends AnonymousGuild {
|
|||||||
if ('preferred_locale' in data) {
|
if ('preferred_locale' in data) {
|
||||||
/**
|
/**
|
||||||
* The preferred locale of the guild, defaults to `en-US`
|
* The preferred locale of the guild, defaults to `en-US`
|
||||||
* @type {string}
|
* @type {Locale}
|
||||||
* @see {@link https://discord.com/developers/docs/dispatch/field-values#predefined-field-values-accepted-locales}
|
* @see {@link https://discord.com/developers/docs/reference#locales}
|
||||||
*/
|
*/
|
||||||
this.preferredLocale = data.preferred_locale;
|
this.preferredLocale = data.preferred_locale;
|
||||||
}
|
}
|
||||||
@@ -808,24 +810,24 @@ class Guild extends AnonymousGuild {
|
|||||||
* The data for editing a guild.
|
* The data for editing a guild.
|
||||||
* @typedef {Object} GuildEditData
|
* @typedef {Object} GuildEditData
|
||||||
* @property {string} [name] The name of the guild
|
* @property {string} [name] The name of the guild
|
||||||
* @property {VerificationLevel|number} [verificationLevel] The verification level of the guild
|
* @property {?(VerificationLevel|number)} [verificationLevel] The verification level of the guild
|
||||||
* @property {ExplicitContentFilterLevel|number} [explicitContentFilter] The level of the explicit content filter
|
* @property {?(ExplicitContentFilterLevel|number)} [explicitContentFilter] The level of the explicit content filter
|
||||||
* @property {VoiceChannelResolvable} [afkChannel] The AFK channel of the guild
|
* @property {?VoiceChannelResolvable} [afkChannel] The AFK channel of the guild
|
||||||
* @property {TextChannelResolvable} [systemChannel] The system channel of the guild
|
* @property {?TextChannelResolvable} [systemChannel] The system channel of the guild
|
||||||
* @property {number} [afkTimeout] The AFK timeout of the guild
|
* @property {number} [afkTimeout] The AFK timeout of the guild
|
||||||
* @property {?(BufferResolvable|Base64Resolvable)} [icon] The icon of the guild
|
* @property {?(BufferResolvable|Base64Resolvable)} [icon] The icon of the guild
|
||||||
* @property {GuildMemberResolvable} [owner] The owner of the guild
|
* @property {GuildMemberResolvable} [owner] The owner of the guild
|
||||||
* @property {?(BufferResolvable|Base64Resolvable)} [splash] The invite splash image of the guild
|
* @property {?(BufferResolvable|Base64Resolvable)} [splash] The invite splash image of the guild
|
||||||
* @property {?(BufferResolvable|Base64Resolvable)} [discoverySplash] The discovery splash image of the guild
|
* @property {?(BufferResolvable|Base64Resolvable)} [discoverySplash] The discovery splash image of the guild
|
||||||
* @property {?(BufferResolvable|Base64Resolvable)} [banner] The banner of the guild
|
* @property {?(BufferResolvable|Base64Resolvable)} [banner] The banner of the guild
|
||||||
* @property {DefaultMessageNotificationLevel|number} [defaultMessageNotifications] The default message notification
|
* @property {?(DefaultMessageNotificationLevel|number)} [defaultMessageNotifications] The default message
|
||||||
* level of the guild
|
* notification level of the guild
|
||||||
* @property {SystemChannelFlagsResolvable} [systemChannelFlags] The system channel flags of the guild
|
* @property {SystemChannelFlagsResolvable} [systemChannelFlags] The system channel flags of the guild
|
||||||
* @property {TextChannelResolvable} [rulesChannel] The rules channel of the guild
|
* @property {?TextChannelResolvable} [rulesChannel] The rules channel of the guild
|
||||||
* @property {TextChannelResolvable} [publicUpdatesChannel] The community updates channel of the guild
|
* @property {?TextChannelResolvable} [publicUpdatesChannel] The community updates channel of the guild
|
||||||
* @property {string} [preferredLocale] The preferred locale of the guild
|
* @property {?string} [preferredLocale] The preferred locale of the guild
|
||||||
* @property {boolean} [premiumProgressBarEnabled] Whether the guild's premium progress bar is enabled
|
* @property {boolean} [premiumProgressBarEnabled] Whether the guild's premium progress bar is enabled
|
||||||
* @property {string} [description] The discovery description of the guild
|
* @property {?string} [description] The discovery description of the guild
|
||||||
* @property {Features[]} [features] The features of the guild
|
* @property {Features[]} [features] The features of the guild
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -906,7 +908,7 @@ class Guild extends AnonymousGuild {
|
|||||||
if (typeof data.description !== 'undefined') {
|
if (typeof data.description !== 'undefined') {
|
||||||
_data.description = data.description;
|
_data.description = data.description;
|
||||||
}
|
}
|
||||||
if (data.preferredLocale) _data.preferred_locale = data.preferredLocale;
|
if (typeof data.preferredLocale !== 'undefined') _data.preferred_locale = data.preferredLocale;
|
||||||
if ('premiumProgressBarEnabled' in data) _data.premium_progress_bar_enabled = data.premiumProgressBarEnabled;
|
if ('premiumProgressBarEnabled' in data) _data.premium_progress_bar_enabled = data.premiumProgressBarEnabled;
|
||||||
const newData = await this.client.api.guilds(this.id).patch({ data: _data, reason });
|
const newData = await this.client.api.guilds(this.id).patch({ data: _data, reason });
|
||||||
return this.client.actions.GuildUpdate.handle(newData).updated;
|
return this.client.actions.GuildUpdate.handle(newData).updated;
|
||||||
@@ -984,7 +986,7 @@ class Guild extends AnonymousGuild {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits the level of the explicit content filter.
|
* Edits the level of the explicit content filter.
|
||||||
* @param {ExplicitContentFilterLevel|number} explicitContentFilter The new level of the explicit content filter
|
* @param {?(ExplicitContentFilterLevel|number)} explicitContentFilter The new level of the explicit content filter
|
||||||
* @param {string} [reason] Reason for changing the level of the guild's explicit content filter
|
* @param {string} [reason] Reason for changing the level of the guild's explicit content filter
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
*/
|
*/
|
||||||
@@ -995,7 +997,7 @@ class Guild extends AnonymousGuild {
|
|||||||
/* eslint-disable max-len */
|
/* eslint-disable max-len */
|
||||||
/**
|
/**
|
||||||
* Edits the setting of the default message notifications of the guild.
|
* Edits the setting of the default message notifications of the guild.
|
||||||
* @param {DefaultMessageNotificationLevel|number} defaultMessageNotifications The new default message notification level of the guild
|
* @param {?(DefaultMessageNotificationLevel|number)} defaultMessageNotifications The new default message notification level of the guild
|
||||||
* @param {string} [reason] Reason for changing the setting of the default message notifications
|
* @param {string} [reason] Reason for changing the setting of the default message notifications
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
*/
|
*/
|
||||||
@@ -1031,7 +1033,7 @@ class Guild extends AnonymousGuild {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits the verification level of the guild.
|
* Edits the verification level of the guild.
|
||||||
* @param {VerificationLevel|number} verificationLevel The new verification level of the guild
|
* @param {?(VerificationLevel|number)} verificationLevel The new verification level of the guild
|
||||||
* @param {string} [reason] Reason for changing the guild's verification level
|
* @param {string} [reason] Reason for changing the guild's verification level
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
* @example
|
* @example
|
||||||
@@ -1046,7 +1048,7 @@ class Guild extends AnonymousGuild {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits the AFK channel of the guild.
|
* Edits the AFK channel of the guild.
|
||||||
* @param {VoiceChannelResolvable} afkChannel The new AFK channel
|
* @param {?VoiceChannelResolvable} afkChannel The new AFK channel
|
||||||
* @param {string} [reason] Reason for changing the guild's AFK channel
|
* @param {string} [reason] Reason for changing the guild's AFK channel
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
* @example
|
* @example
|
||||||
@@ -1061,7 +1063,7 @@ class Guild extends AnonymousGuild {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits the system channel of the guild.
|
* Edits the system channel of the guild.
|
||||||
* @param {TextChannelResolvable} systemChannel The new system channel
|
* @param {?TextChannelResolvable} systemChannel The new system channel
|
||||||
* @param {string} [reason] Reason for changing the guild's system channel
|
* @param {string} [reason] Reason for changing the guild's system channel
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
* @example
|
* @example
|
||||||
@@ -1166,7 +1168,7 @@ class Guild extends AnonymousGuild {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits the rules channel of the guild.
|
* Edits the rules channel of the guild.
|
||||||
* @param {TextChannelResolvable} rulesChannel The new rules channel
|
* @param {?TextChannelResolvable} rulesChannel The new rules channel
|
||||||
* @param {string} [reason] Reason for changing the guild's rules channel
|
* @param {string} [reason] Reason for changing the guild's rules channel
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
* @example
|
* @example
|
||||||
@@ -1181,7 +1183,7 @@ class Guild extends AnonymousGuild {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits the community updates channel of the guild.
|
* Edits the community updates channel of the guild.
|
||||||
* @param {TextChannelResolvable} publicUpdatesChannel The new community updates channel
|
* @param {?TextChannelResolvable} publicUpdatesChannel The new community updates channel
|
||||||
* @param {string} [reason] Reason for changing the guild's community updates channel
|
* @param {string} [reason] Reason for changing the guild's community updates channel
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
* @example
|
* @example
|
||||||
@@ -1196,7 +1198,7 @@ class Guild extends AnonymousGuild {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits the preferred locale of the guild.
|
* Edits the preferred locale of the guild.
|
||||||
* @param {string} preferredLocale The new preferred locale of the guild
|
* @param {?string} preferredLocale The new preferred locale of the guild
|
||||||
* @param {string} [reason] Reason for changing the guild's preferred locale
|
* @param {string} [reason] Reason for changing the guild's preferred locale
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
* @example
|
* @example
|
||||||
|
|||||||
@@ -398,9 +398,9 @@ class GuildAuditLogsEntry {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Specific property changes
|
* Specific property changes
|
||||||
* @type {?AuditLogChange[]}
|
* @type {AuditLogChange[]}
|
||||||
*/
|
*/
|
||||||
this.changes = data.changes?.map(c => ({ key: c.key, old: c.old_value, new: c.new_value })) ?? null;
|
this.changes = data.changes?.map(c => ({ key: c.key, old: c.old_value, new: c.new_value })) ?? [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The entry's id
|
* The entry's id
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { Channel } = require('./Channel');
|
const { Channel } = require('./Channel');
|
||||||
const PermissionOverwrites = require('./PermissionOverwrites');
|
|
||||||
const { Error } = require('../errors');
|
const { Error } = require('../errors');
|
||||||
const PermissionOverwriteManager = require('../managers/PermissionOverwriteManager');
|
const PermissionOverwriteManager = require('../managers/PermissionOverwriteManager');
|
||||||
const { ChannelTypes, VoiceBasedChannelTypes } = require('../util/Constants');
|
const { VoiceBasedChannelTypes } = require('../util/Constants');
|
||||||
const Permissions = require('../util/Permissions');
|
const Permissions = require('../util/Permissions');
|
||||||
const Util = require('../util/Util');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a guild channel from any of the following:
|
* Represents a guild channel from any of the following:
|
||||||
@@ -262,27 +260,6 @@ class GuildChannel extends Channel {
|
|||||||
return this.guild.members.cache.filter(m => this.permissionsFor(m).has(Permissions.FLAGS.VIEW_CHANNEL, false));
|
return this.guild.members.cache.filter(m => this.permissionsFor(m).has(Permissions.FLAGS.VIEW_CHANNEL, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The data for a guild channel.
|
|
||||||
* @typedef {Object} ChannelData
|
|
||||||
* @property {string} [name] The name of the channel
|
|
||||||
* @property {ChannelType} [type] The type of the channel (only conversion between text and news is supported)
|
|
||||||
* @property {number} [position] The position of the channel
|
|
||||||
* @property {string} [topic] The topic of the text channel
|
|
||||||
* @property {boolean} [nsfw] Whether the channel is NSFW
|
|
||||||
* @property {number} [bitrate] The bitrate of the voice channel
|
|
||||||
* @property {number} [userLimit] The user limit of the voice channel
|
|
||||||
* @property {?CategoryChannelResolvable} [parent] The parent of the channel
|
|
||||||
* @property {boolean} [lockPermissions]
|
|
||||||
* Lock the permissions of the channel to what the parent's permissions are
|
|
||||||
* @property {OverwriteResolvable[]|Collection<Snowflake, OverwriteResolvable>} [permissionOverwrites]
|
|
||||||
* Permission overwrites for the channel
|
|
||||||
* @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the channel in seconds
|
|
||||||
* @property {ThreadAutoArchiveDuration} [defaultAutoArchiveDuration]
|
|
||||||
* The default auto archive duration for all new threads in this channel
|
|
||||||
* @property {?string} [rtcRegion] The RTC region of the channel
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits the channel.
|
* Edits the channel.
|
||||||
* @param {ChannelData} data The new data for the channel
|
* @param {ChannelData} data The new data for the channel
|
||||||
@@ -294,64 +271,8 @@ class GuildChannel extends Channel {
|
|||||||
* .then(console.log)
|
* .then(console.log)
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
async edit(data, reason) {
|
edit(data, reason) {
|
||||||
data.parent &&= this.client.channels.resolveId(data.parent);
|
return this.guild.channels.edit(this, data, reason);
|
||||||
|
|
||||||
if (typeof data.position !== 'undefined') {
|
|
||||||
const updatedChannels = await Util.setPosition(
|
|
||||||
this,
|
|
||||||
data.position,
|
|
||||||
false,
|
|
||||||
this.guild._sortedChannels(this),
|
|
||||||
this.client.api.guilds(this.guild.id).channels,
|
|
||||||
reason,
|
|
||||||
);
|
|
||||||
this.client.actions.GuildChannelsPositionUpdate.handle({
|
|
||||||
guild_id: this.guild.id,
|
|
||||||
channels: updatedChannels,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let permission_overwrites;
|
|
||||||
|
|
||||||
if (data.permissionOverwrites) {
|
|
||||||
permission_overwrites = data.permissionOverwrites.map(o => PermissionOverwrites.resolve(o, this.guild));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.lockPermissions) {
|
|
||||||
if (data.parent) {
|
|
||||||
const newParent = this.guild.channels.resolve(data.parent);
|
|
||||||
if (newParent?.type === 'GUILD_CATEGORY') {
|
|
||||||
permission_overwrites = newParent.permissionOverwrites.cache.map(o =>
|
|
||||||
PermissionOverwrites.resolve(o, this.guild),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if (this.parent) {
|
|
||||||
permission_overwrites = this.parent.permissionOverwrites.cache.map(o =>
|
|
||||||
PermissionOverwrites.resolve(o, this.guild),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const newData = await this.client.api.channels(this.id).patch({
|
|
||||||
data: {
|
|
||||||
name: (data.name ?? this.name).trim(),
|
|
||||||
type: ChannelTypes[data.type],
|
|
||||||
topic: data.topic,
|
|
||||||
nsfw: data.nsfw,
|
|
||||||
bitrate: data.bitrate ?? this.bitrate,
|
|
||||||
user_limit: data.userLimit ?? this.userLimit,
|
|
||||||
rtc_region: data.rtcRegion ?? this.rtcRegion,
|
|
||||||
parent_id: data.parent,
|
|
||||||
lock_permissions: data.lockPermissions,
|
|
||||||
rate_limit_per_user: data.rateLimitPerUser,
|
|
||||||
default_auto_archive_duration: data.defaultAutoArchiveDuration,
|
|
||||||
permission_overwrites,
|
|
||||||
},
|
|
||||||
reason,
|
|
||||||
});
|
|
||||||
|
|
||||||
return this.client.actions.ChannelUpdate.handle(newData).updated;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -415,30 +336,10 @@ class GuildChannel extends Channel {
|
|||||||
* .then(newChannel => console.log(`Channel's new position is ${newChannel.position}`))
|
* .then(newChannel => console.log(`Channel's new position is ${newChannel.position}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
async setPosition(position, { relative, reason } = {}) {
|
setPosition(position, options = {}) {
|
||||||
const updatedChannels = await Util.setPosition(
|
return this.guild.channels.setPosition(this, position, options);
|
||||||
this,
|
|
||||||
position,
|
|
||||||
relative,
|
|
||||||
this.guild._sortedChannels(this),
|
|
||||||
this.client.api.guilds(this.guild.id).channels,
|
|
||||||
reason,
|
|
||||||
);
|
|
||||||
this.client.actions.GuildChannelsPositionUpdate.handle({
|
|
||||||
guild_id: this.guild.id,
|
|
||||||
channels: updatedChannels,
|
|
||||||
});
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Data that can be resolved to an Application. This can be:
|
|
||||||
* * An Application
|
|
||||||
* * An Activity with associated Application
|
|
||||||
* * A Snowflake
|
|
||||||
* @typedef {Application|Snowflake} ApplicationResolvable
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options used to clone a guild channel.
|
* Options used to clone a guild channel.
|
||||||
* @typedef {GuildChannelCreateOptions} GuildChannelCloneOptions
|
* @typedef {GuildChannelCreateOptions} GuildChannelCloneOptions
|
||||||
@@ -544,7 +445,7 @@ class GuildChannel extends Channel {
|
|||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
async delete(reason) {
|
async delete(reason) {
|
||||||
await this.client.api.channels(this.id).delete({ reason });
|
await this.guild.channels.delete(this.id, reason);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,18 +72,8 @@ class GuildEmoji extends BaseGuildEmoji {
|
|||||||
* Fetches the author for this emoji
|
* Fetches the author for this emoji
|
||||||
* @returns {Promise<User>}
|
* @returns {Promise<User>}
|
||||||
*/
|
*/
|
||||||
async fetchAuthor() {
|
fetchAuthor() {
|
||||||
if (this.managed) {
|
return this.guild.emojis.fetchAuthor(this);
|
||||||
throw new Error('EMOJI_MANAGED');
|
|
||||||
} else {
|
|
||||||
if (!this.guild.me) throw new Error('GUILD_UNCACHED_ME');
|
|
||||||
if (!this.guild.me.permissions.has(Permissions.FLAGS.MANAGE_EMOJIS_AND_STICKERS)) {
|
|
||||||
throw new Error('MISSING_MANAGE_EMOJIS_AND_STICKERS_PERMISSION', this.guild);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const data = await this.client.api.guilds(this.guild.id).emojis(this.id).get();
|
|
||||||
this._patch(data);
|
|
||||||
return this.author;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -137,7 +127,7 @@ class GuildEmoji extends BaseGuildEmoji {
|
|||||||
* @returns {Promise<GuildEmoji>}
|
* @returns {Promise<GuildEmoji>}
|
||||||
*/
|
*/
|
||||||
async delete(reason) {
|
async delete(reason) {
|
||||||
await this.client.api.guilds(this.guild.id).emojis(this.id).delete({ reason });
|
await this.guild.emojis.delete(this, reason);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -300,7 +300,11 @@ class GuildMember extends Base {
|
|||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
get moderatable() {
|
get moderatable() {
|
||||||
return this.manageable && (this.guild.me?.permissions.has(Permissions.FLAGS.MODERATE_MEMBERS) ?? false);
|
return (
|
||||||
|
!this.permissions.has(Permissions.FLAGS.ADMINISTRATOR) &&
|
||||||
|
this.manageable &&
|
||||||
|
(this.guild.me?.permissions.has(Permissions.FLAGS.MODERATE_MEMBERS) ?? false)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
const { Collection } = require('@discordjs/collection');
|
const { Collection } = require('@discordjs/collection');
|
||||||
const Base = require('./Base');
|
const Base = require('./Base');
|
||||||
const GuildPreviewEmoji = require('./GuildPreviewEmoji');
|
const GuildPreviewEmoji = require('./GuildPreviewEmoji');
|
||||||
|
const { Sticker } = require('./Sticker');
|
||||||
const SnowflakeUtil = require('../util/SnowflakeUtil');
|
const SnowflakeUtil = require('../util/SnowflakeUtil');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -103,6 +104,15 @@ class GuildPreview extends Base {
|
|||||||
for (const emoji of data.emojis) {
|
for (const emoji of data.emojis) {
|
||||||
this.emojis.set(emoji.id, new GuildPreviewEmoji(this.client, emoji, this));
|
this.emojis.set(emoji.id, new GuildPreviewEmoji(this.client, emoji, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection of stickers belonging to this guild
|
||||||
|
* @type {Collection<Snowflake, Sticker>}
|
||||||
|
*/
|
||||||
|
this.stickers = data.stickers.reduce(
|
||||||
|
(stickers, sticker) => stickers.set(sticker.id, new Sticker(this.client, sticker)),
|
||||||
|
new Collection(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* The timestamp this guild was created at
|
* The timestamp this guild was created at
|
||||||
|
|||||||
@@ -156,6 +156,25 @@ class GuildScheduledEvent extends Base {
|
|||||||
} else {
|
} else {
|
||||||
this.entityMetadata ??= null;
|
this.entityMetadata ??= null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('image' in data) {
|
||||||
|
/**
|
||||||
|
* The cover image hash for this scheduled event
|
||||||
|
* @type {?string}
|
||||||
|
*/
|
||||||
|
this.image = data.image;
|
||||||
|
} else {
|
||||||
|
this.image ??= null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL of this scheduled event's cover image
|
||||||
|
* @param {StaticImageURLOptions} [options={}] Options for image URL
|
||||||
|
* @returns {?string}
|
||||||
|
*/
|
||||||
|
coverImageURL({ format, size } = {}) {
|
||||||
|
return this.image && this.client.rest.cdn.guildScheduledEventCover(this.id, this.image, format, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ class IntegrationApplication extends Application {
|
|||||||
/**
|
/**
|
||||||
* The application's summary
|
* The application's summary
|
||||||
* @type {?string}
|
* @type {?string}
|
||||||
|
* @deprecated This property is no longer being sent by the API.
|
||||||
*/
|
*/
|
||||||
this.summary = data.summary;
|
this.summary = data.summary;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -69,11 +69,65 @@ class Interaction extends Base {
|
|||||||
*/
|
*/
|
||||||
this.version = data.version;
|
this.version = data.version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of permissions the application or bot has within the channel the interaction was sent from
|
||||||
|
* @type {?Readonly<Permissions>}
|
||||||
|
*/
|
||||||
|
this.appPermissions = data.app_permissions ? new Permissions(data.app_permissions).freeze() : null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The permissions of the member, if one exists, in the channel this interaction was executed in
|
* The permissions of the member, if one exists, in the channel this interaction was executed in
|
||||||
* @type {?Readonly<Permissions>}
|
* @type {?Readonly<Permissions>}
|
||||||
*/
|
*/
|
||||||
this.memberPermissions = data.member?.permissions ? new Permissions(data.member.permissions).freeze() : null;
|
this.memberPermissions = data.member?.permissions ? new Permissions(data.member.permissions).freeze() : null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Discord locale string, possible values are:
|
||||||
|
* * en-US (English, US)
|
||||||
|
* * en-GB (English, UK)
|
||||||
|
* * bg (Bulgarian)
|
||||||
|
* * zh-CN (Chinese, China)
|
||||||
|
* * zh-TW (Chinese, Taiwan)
|
||||||
|
* * hr (Croatian)
|
||||||
|
* * cs (Czech)
|
||||||
|
* * da (Danish)
|
||||||
|
* * nl (Dutch)
|
||||||
|
* * fi (Finnish)
|
||||||
|
* * fr (French)
|
||||||
|
* * de (German)
|
||||||
|
* * el (Greek)
|
||||||
|
* * hi (Hindi)
|
||||||
|
* * hu (Hungarian)
|
||||||
|
* * it (Italian)
|
||||||
|
* * ja (Japanese)
|
||||||
|
* * ko (Korean)
|
||||||
|
* * lt (Lithuanian)
|
||||||
|
* * no (Norwegian)
|
||||||
|
* * pl (Polish)
|
||||||
|
* * pt-BR (Portuguese, Brazilian)
|
||||||
|
* * ro (Romanian, Romania)
|
||||||
|
* * ru (Russian)
|
||||||
|
* * es-ES (Spanish)
|
||||||
|
* * sv-SE (Swedish)
|
||||||
|
* * th (Thai)
|
||||||
|
* * tr (Turkish)
|
||||||
|
* * uk (Ukrainian)
|
||||||
|
* * vi (Vietnamese)
|
||||||
|
* @see {@link https://discord.com/developers/docs/reference#locales}
|
||||||
|
* @typedef {string} Locale
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The locale of the user who invoked this interaction
|
||||||
|
* @type {Locale}
|
||||||
|
*/
|
||||||
|
this.locale = data.locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The preferred locale from the guild this interaction was sent in
|
||||||
|
* @type {?Locale}
|
||||||
|
*/
|
||||||
|
this.guildLocale = data.guild_locale ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -160,6 +214,14 @@ class Interaction extends Base {
|
|||||||
return InteractionTypes[this.type] === InteractionTypes.APPLICATION_COMMAND && typeof this.targetId !== 'undefined';
|
return InteractionTypes[this.type] === InteractionTypes.APPLICATION_COMMAND && typeof this.targetId !== 'undefined';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether this interaction is a {@link ModalSubmitInteraction}
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
isModalSubmit() {
|
||||||
|
return InteractionTypes[this.type] === InteractionTypes.MODAL_SUBMIT;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether this interaction is a {@link UserContextMenuInteraction}
|
* Indicates whether this interaction is a {@link UserContextMenuInteraction}
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
@@ -213,6 +275,16 @@ class Interaction extends Base {
|
|||||||
MessageComponentTypes[this.componentType] === MessageComponentTypes.SELECT_MENU
|
MessageComponentTypes[this.componentType] === MessageComponentTypes.SELECT_MENU
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether this interaction can be replied to.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
isRepliable() {
|
||||||
|
return ![InteractionTypes.PING, InteractionTypes.APPLICATION_COMMAND_AUTOCOMPLETE].includes(
|
||||||
|
InteractionTypes[this.type],
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Interaction;
|
module.exports = Interaction;
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ const { InteractionTypes, MessageComponentTypes } = require('../util/Constants')
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {CollectorOptions} InteractionCollectorOptions
|
* @typedef {CollectorOptions} InteractionCollectorOptions
|
||||||
* @property {TextBasedChannels} [channel] The channel to listen to interactions from
|
* @property {TextBasedChannelsResolvable} [channel] The channel to listen to interactions from
|
||||||
* @property {MessageComponentType} [componentType] The type of component to listen for
|
* @property {MessageComponentType} [componentType] The type of component to listen for
|
||||||
* @property {Guild} [guild] The guild to listen to interactions from
|
* @property {GuildResolvable} [guild] The guild to listen to interactions from
|
||||||
* @property {InteractionType} [interactionType] The type of interaction to listen for
|
* @property {InteractionType} [interactionType] The type of interaction to listen for
|
||||||
* @property {number} [max] The maximum total amount of interactions to collect
|
* @property {number} [max] The maximum total amount of interactions to collect
|
||||||
* @property {number} [maxComponents] The maximum number of components to collect
|
* @property {number} [maxComponents] The maximum number of components to collect
|
||||||
|
|||||||
@@ -197,8 +197,11 @@ class Invite extends Base {
|
|||||||
this.createdTimestamp ??= null;
|
this.createdTimestamp ??= null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('expires_at' in data) this._expiresTimestamp = new Date(data.expires_at).getTime();
|
if ('expires_at' in data) {
|
||||||
else this._expiresTimestamp ??= null;
|
this._expiresTimestamp = data.expires_at && Date.parse(data.expires_at);
|
||||||
|
} else {
|
||||||
|
this._expiresTimestamp ??= null;
|
||||||
|
}
|
||||||
|
|
||||||
if ('stage_instance' in data) {
|
if ('stage_instance' in data) {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -331,7 +331,8 @@ class Message extends Base {
|
|||||||
* @typedef {Object} MessageInteraction
|
* @typedef {Object} MessageInteraction
|
||||||
* @property {Snowflake} id The interaction's id
|
* @property {Snowflake} id The interaction's id
|
||||||
* @property {InteractionType} type The type of the interaction
|
* @property {InteractionType} type The type of the interaction
|
||||||
* @property {string} commandName The name of the interaction's application command
|
* @property {string} commandName The name of the interaction's application command,
|
||||||
|
* as well as the subcommand and subcommand group, where applicable
|
||||||
* @property {User} user The user that invoked the interaction
|
* @property {User} user The user that invoked the interaction
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -383,7 +384,7 @@ class Message extends Base {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The channel that the message was sent in
|
* The channel that the message was sent in
|
||||||
* @type {TextChannel|DMChannel|NewsChannel|ThreadChannel}
|
* @type {TextBasedChannels}
|
||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
get channel() {
|
get channel() {
|
||||||
@@ -720,6 +721,7 @@ class Message extends Base {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Pins this message to the channel's pinned messages.
|
* Pins this message to the channel's pinned messages.
|
||||||
|
* @param {string} [reason] Reason for pinning
|
||||||
* @returns {Promise<Message>}
|
* @returns {Promise<Message>}
|
||||||
* @example
|
* @example
|
||||||
* // Pin a message
|
* // Pin a message
|
||||||
@@ -727,14 +729,15 @@ class Message extends Base {
|
|||||||
* .then(console.log)
|
* .then(console.log)
|
||||||
* .catch(console.error)
|
* .catch(console.error)
|
||||||
*/
|
*/
|
||||||
async pin() {
|
async pin(reason) {
|
||||||
if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
|
if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
|
||||||
await this.channel.messages.pin(this.id);
|
await this.channel.messages.pin(this.id, reason);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unpins this message from the channel's pinned messages.
|
* Unpins this message from the channel's pinned messages.
|
||||||
|
* @param {string} [reason] Reason for unpinning
|
||||||
* @returns {Promise<Message>}
|
* @returns {Promise<Message>}
|
||||||
* @example
|
* @example
|
||||||
* // Unpin a message
|
* // Unpin a message
|
||||||
@@ -742,9 +745,9 @@ class Message extends Base {
|
|||||||
* .then(console.log)
|
* .then(console.log)
|
||||||
* .catch(console.error)
|
* .catch(console.error)
|
||||||
*/
|
*/
|
||||||
async unpin() {
|
async unpin(reason) {
|
||||||
if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
|
if (!this.channel) throw new Error('CHANNEL_NOT_CACHED');
|
||||||
await this.channel.messages.unpin(this.id);
|
await this.channel.messages.unpin(this.id, reason);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,14 +12,16 @@ class MessageActionRow extends BaseMessageComponent {
|
|||||||
* Components that can be placed in an action row
|
* Components that can be placed in an action row
|
||||||
* * MessageButton
|
* * MessageButton
|
||||||
* * MessageSelectMenu
|
* * MessageSelectMenu
|
||||||
* @typedef {MessageButton|MessageSelectMenu} MessageActionRowComponent
|
* * TextInputComponent
|
||||||
|
* @typedef {MessageButton|MessageSelectMenu|TextInputComponent} MessageActionRowComponent
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options for components that can be placed in an action row
|
* Options for components that can be placed in an action row
|
||||||
* * MessageButtonOptions
|
* * MessageButtonOptions
|
||||||
* * MessageSelectMenuOptions
|
* * MessageSelectMenuOptions
|
||||||
* @typedef {MessageButtonOptions|MessageSelectMenuOptions} MessageActionRowComponentOptions
|
* * TextInputComponentOptions
|
||||||
|
* @typedef {MessageButtonOptions|MessageSelectMenuOptions|TextInputComponentOptions} MessageActionRowComponentOptions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ class MessageAttachment {
|
|||||||
|
|
||||||
if ('content_type' in data) {
|
if ('content_type' in data) {
|
||||||
/**
|
/**
|
||||||
* This media type of this attachment
|
* The media type of this attachment
|
||||||
* @type {?string}
|
* @type {?string}
|
||||||
*/
|
*/
|
||||||
this.contentType = data.content_type;
|
this.contentType = data.content_type;
|
||||||
|
|||||||
@@ -101,6 +101,8 @@ class MessageComponentInteraction extends Interaction {
|
|||||||
followUp() {}
|
followUp() {}
|
||||||
deferUpdate() {}
|
deferUpdate() {}
|
||||||
update() {}
|
update() {}
|
||||||
|
showModal() {}
|
||||||
|
awaitModalSubmit() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
InteractionResponses.applyToClass(MessageComponentInteraction);
|
InteractionResponses.applyToClass(MessageComponentInteraction);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const Util = require('../util/Util');
|
|||||||
|
|
||||||
let deprecationEmittedForSetAuthor = false;
|
let deprecationEmittedForSetAuthor = false;
|
||||||
let deprecationEmittedForSetFooter = false;
|
let deprecationEmittedForSetFooter = false;
|
||||||
|
let deprecationEmittedForAddField = false;
|
||||||
|
|
||||||
// TODO: Remove the deprecated code for `setAuthor()` and `setFooter()`.
|
// TODO: Remove the deprecated code for `setAuthor()` and `setFooter()`.
|
||||||
|
|
||||||
@@ -209,7 +210,7 @@ class MessageEmbed {
|
|||||||
this.provider = data.provider
|
this.provider = data.provider
|
||||||
? {
|
? {
|
||||||
name: data.provider.name,
|
name: data.provider.name,
|
||||||
url: data.provider.name,
|
url: data.provider.url,
|
||||||
}
|
}
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
@@ -314,8 +315,18 @@ class MessageEmbed {
|
|||||||
* @param {string} value The value of this field
|
* @param {string} value The value of this field
|
||||||
* @param {boolean} [inline=false] If this field will be displayed inline
|
* @param {boolean} [inline=false] If this field will be displayed inline
|
||||||
* @returns {MessageEmbed}
|
* @returns {MessageEmbed}
|
||||||
|
* @deprecated This method is a wrapper for {@link MessageEmbed#addFields}. Use that instead.
|
||||||
*/
|
*/
|
||||||
addField(name, value, inline) {
|
addField(name, value, inline) {
|
||||||
|
if (!deprecationEmittedForAddField) {
|
||||||
|
process.emitWarning(
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
'MessageEmbed#addField is deprecated and will be removed in the next major update. Use MessageEmbed#addFields instead.',
|
||||||
|
'DeprecationWarning',
|
||||||
|
);
|
||||||
|
|
||||||
|
deprecationEmittedForAddField = true;
|
||||||
|
}
|
||||||
return this.addFields({ name, value, inline });
|
return this.addFields({ name, value, inline });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,7 +441,7 @@ class MessageEmbed {
|
|||||||
*/
|
*/
|
||||||
setFooter(options, deprecatedIconURL) {
|
setFooter(options, deprecatedIconURL) {
|
||||||
if (options === null) {
|
if (options === null) {
|
||||||
this.footer = {};
|
this.footer = undefined;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,6 +93,13 @@ class MessageMentions {
|
|||||||
*/
|
*/
|
||||||
this._channels = null;
|
this._channels = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cached users for {@link MessageMentions#parsedUsers}
|
||||||
|
* @type {?Collection<Snowflake, User>}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this._parsedUsers = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crossposted channel data.
|
* Crossposted channel data.
|
||||||
* @typedef {Object} CrosspostedChannel
|
* @typedef {Object} CrosspostedChannel
|
||||||
@@ -168,33 +175,64 @@ class MessageMentions {
|
|||||||
return this._channels;
|
return this._channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any user mentions that were included in the message content
|
||||||
|
* <info>Order as they appear first in the message content</info>
|
||||||
|
* @type {Collection<Snowflake, User>}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get parsedUsers() {
|
||||||
|
if (this._parsedUsers) return this._parsedUsers;
|
||||||
|
this._parsedUsers = new Collection();
|
||||||
|
let matches;
|
||||||
|
while ((matches = this.constructor.USERS_PATTERN.exec(this._content)) !== null) {
|
||||||
|
const user = this.client.users.cache.get(matches[1]);
|
||||||
|
if (user) this._parsedUsers.set(user.id, user);
|
||||||
|
}
|
||||||
|
return this._parsedUsers;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options used to check for a mention.
|
* Options used to check for a mention.
|
||||||
* @typedef {Object} MessageMentionsHasOptions
|
* @typedef {Object} MessageMentionsHasOptions
|
||||||
* @property {boolean} [ignoreDirect=false] Whether to ignore direct mentions to the item
|
* @property {boolean} [ignoreDirect=false] Whether to ignore direct mentions to the item
|
||||||
* @property {boolean} [ignoreRoles=false] Whether to ignore role mentions to a guild member
|
* @property {boolean} [ignoreRoles=false] Whether to ignore role mentions to a guild member
|
||||||
* @property {boolean} [ignoreEveryone=false] Whether to ignore everyone/here mentions
|
* @property {boolean} [ignoreRepliedUser=false] Whether to ignore replied user mention to an user
|
||||||
|
* @property {boolean} [ignoreEveryone=false] Whether to ignore `@everyone`/`@here` mentions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a user, guild member, role, or channel is mentioned.
|
* Checks if a user, guild member, thread member, role, or channel is mentioned.
|
||||||
* Takes into account user mentions, role mentions, and `@everyone`/`@here` mentions.
|
* Takes into account user mentions, role mentions, channel mentions,
|
||||||
|
* replied user mention, and `@everyone`/`@here` mentions.
|
||||||
* @param {UserResolvable|RoleResolvable|ChannelResolvable} data The User/Role/Channel to check for
|
* @param {UserResolvable|RoleResolvable|ChannelResolvable} data The User/Role/Channel to check for
|
||||||
* @param {MessageMentionsHasOptions} [options] The options for the check
|
* @param {MessageMentionsHasOptions} [options] The options for the check
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
has(data, { ignoreDirect = false, ignoreRoles = false, ignoreEveryone = false } = {}) {
|
has(data, { ignoreDirect = false, ignoreRoles = false, ignoreRepliedUser = false, ignoreEveryone = false } = {}) {
|
||||||
if (!ignoreEveryone && this.everyone) return true;
|
const user = this.client.users.resolve(data);
|
||||||
const { GuildMember } = require('./GuildMember');
|
|
||||||
if (!ignoreRoles && data instanceof GuildMember) {
|
if (!ignoreEveryone && user && this.everyone) return true;
|
||||||
for (const role of this.roles.values()) if (data.roles.cache.has(role.id)) return true;
|
|
||||||
}
|
const userWasRepliedTo = user && this.repliedUser?.id === user.id;
|
||||||
|
|
||||||
|
if (!ignoreRepliedUser && userWasRepliedTo && this.users.has(user.id)) return true;
|
||||||
|
|
||||||
if (!ignoreDirect) {
|
if (!ignoreDirect) {
|
||||||
const id =
|
if (user && (!ignoreRepliedUser || this.parsedUsers.has(user.id)) && this.users.has(user.id)) return true;
|
||||||
this.guild?.roles.resolveId(data) ?? this.client.channels.resolveId(data) ?? this.client.users.resolveId(data);
|
|
||||||
|
|
||||||
return typeof id === 'string' && (this.users.has(id) || this.channels.has(id) || this.roles.has(id));
|
const role = this.guild?.roles.resolve(data);
|
||||||
|
if (role && this.roles.has(role.id)) return true;
|
||||||
|
|
||||||
|
const channel = this.client.channels.resolve(data);
|
||||||
|
if (channel && this.channels.has(channel.id)) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ignoreRoles) {
|
||||||
|
const member = this.guild?.members.resolve(data);
|
||||||
|
if (member) {
|
||||||
|
for (const mentionedRole of this.roles.values()) if (member.roles.cache.has(mentionedRole.id)) return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -148,11 +148,17 @@ class MessagePayload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let flags;
|
let flags;
|
||||||
if (this.isMessage || this.isMessageManager) {
|
if (
|
||||||
|
typeof this.options.flags !== 'undefined' ||
|
||||||
|
(this.isMessage && typeof this.options.reply === 'undefined') ||
|
||||||
|
this.isMessageManager
|
||||||
|
) {
|
||||||
// eslint-disable-next-line eqeqeq
|
// eslint-disable-next-line eqeqeq
|
||||||
flags = this.options.flags != null ? new MessageFlags(this.options.flags).bitfield : this.target.flags?.bitfield;
|
flags = this.options.flags != null ? new MessageFlags(this.options.flags).bitfield : this.target.flags?.bitfield;
|
||||||
} else if (isInteraction && this.options.ephemeral) {
|
}
|
||||||
flags = MessageFlags.FLAGS.EPHEMERAL;
|
|
||||||
|
if (isInteraction && this.options.ephemeral) {
|
||||||
|
flags |= MessageFlags.FLAGS.EPHEMERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
let allowedMentions =
|
let allowedMentions =
|
||||||
@@ -271,7 +277,7 @@ module.exports = MessagePayload;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A target for a message.
|
* A target for a message.
|
||||||
* @typedef {TextChannel|DMChannel|User|GuildMember|Webhook|WebhookClient|Interaction|InteractionWebhook|
|
* @typedef {TextBasedChannels|User|GuildMember|Webhook|WebhookClient|Interaction|InteractionWebhook|
|
||||||
* Message|MessageManager} MessageTarget
|
* Message|MessageManager} MessageTarget
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ class MessageReaction {
|
|||||||
if (this.partial) return;
|
if (this.partial) return;
|
||||||
this.users.cache.set(user.id, user);
|
this.users.cache.set(user.id, user);
|
||||||
if (!this.me || user.id !== this.message.client.user.id || this.count === 0) this.count++;
|
if (!this.me || user.id !== this.message.client.user.id || this.count === 0) this.count++;
|
||||||
this.me ??= user.id === this.message.client.user.id;
|
this.me ||= user.id === this.message.client.user.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
_remove(user) {
|
_remove(user) {
|
||||||
|
|||||||
103
src/structures/Modal.js
Normal file
103
src/structures/Modal.js
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const BaseMessageComponent = require('./BaseMessageComponent');
|
||||||
|
const Util = require('../util/Util');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a modal (form) to be shown in response to an interaction
|
||||||
|
*/
|
||||||
|
class Modal {
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ModalOptions
|
||||||
|
* @property {string} [customId] A unique string to be sent in the interaction when clicked
|
||||||
|
* @property {string} [title] The title to be displayed on this modal
|
||||||
|
* @property {MessageActionRow[]|MessageActionRowOptions[]} [components]
|
||||||
|
* Action rows containing interactive components for the modal (text input components)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Modal|ModalOptions} data Modal to clone or raw data
|
||||||
|
* @param {Client} client The client constructing this Modal, if provided
|
||||||
|
*/
|
||||||
|
constructor(data = {}, client = null) {
|
||||||
|
/**
|
||||||
|
* A list of MessageActionRows in the modal
|
||||||
|
* @type {MessageActionRow[]}
|
||||||
|
*/
|
||||||
|
this.components = data.components?.map(c => BaseMessageComponent.create(c, client)) ?? [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A unique string to be sent in the interaction when submitted
|
||||||
|
* @type {?string}
|
||||||
|
*/
|
||||||
|
this.customId = data.custom_id ?? data.customId ?? null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The title to be displayed on this modal
|
||||||
|
* @type {?string}
|
||||||
|
*/
|
||||||
|
this.title = data.title ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds components to the modal.
|
||||||
|
* @param {...MessageActionRowResolvable[]} components The components to add
|
||||||
|
* @returns {Modal}
|
||||||
|
*/
|
||||||
|
addComponents(...components) {
|
||||||
|
this.components.push(...components.flat(Infinity).map(c => BaseMessageComponent.create(c)));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the components of the modal.
|
||||||
|
* @param {...MessageActionRowResolvable[]} components The components to set
|
||||||
|
* @returns {Modal}
|
||||||
|
*/
|
||||||
|
setComponents(...components) {
|
||||||
|
this.spliceComponents(0, this.components.length, components);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the custom id for this modal
|
||||||
|
* @param {string} customId A unique string to be sent in the interaction when submitted
|
||||||
|
* @returns {Modal}
|
||||||
|
*/
|
||||||
|
setCustomId(customId) {
|
||||||
|
this.customId = Util.verifyString(customId, RangeError, 'MODAL_CUSTOM_ID');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes, replaces, and inserts components in the modal.
|
||||||
|
* @param {number} index The index to start at
|
||||||
|
* @param {number} deleteCount The number of components to remove
|
||||||
|
* @param {...MessageActionRowResolvable[]} [components] The replacing components
|
||||||
|
* @returns {Modal}
|
||||||
|
*/
|
||||||
|
spliceComponents(index, deleteCount, ...components) {
|
||||||
|
this.components.splice(index, deleteCount, ...components.flat(Infinity).map(c => BaseMessageComponent.create(c)));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the title of this modal
|
||||||
|
* @param {string} title The title to be displayed on this modal
|
||||||
|
* @returns {Modal}
|
||||||
|
*/
|
||||||
|
setTitle(title) {
|
||||||
|
this.title = Util.verifyString(title, RangeError, 'MODAL_TITLE');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
components: this.components.map(c => c.toJSON()),
|
||||||
|
custom_id: this.customId,
|
||||||
|
title: this.title,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Modal;
|
||||||
53
src/structures/ModalSubmitFieldsResolver.js
Normal file
53
src/structures/ModalSubmitFieldsResolver.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { TypeError } = require('../errors');
|
||||||
|
const { MessageComponentTypes } = require('../util/Constants');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A resolver for modal submit interaction text inputs.
|
||||||
|
*/
|
||||||
|
class ModalSubmitFieldsResolver {
|
||||||
|
constructor(components) {
|
||||||
|
/**
|
||||||
|
* The components within the modal
|
||||||
|
* @type {PartialModalActionRow[]} The components in the modal
|
||||||
|
*/
|
||||||
|
this.components = components;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The extracted fields from the modal
|
||||||
|
* @type {PartialInputTextData[]} The fields in the modal
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
get _fields() {
|
||||||
|
return this.components.reduce((previous, next) => previous.concat(next.components), []);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a field given a custom id from a component
|
||||||
|
* @param {string} customId The custom id of the component
|
||||||
|
* @returns {?PartialInputTextData}
|
||||||
|
*/
|
||||||
|
getField(customId) {
|
||||||
|
const field = this._fields.find(f => f.customId === customId);
|
||||||
|
if (!field) throw new TypeError('MODAL_SUBMIT_INTERACTION_FIELD_NOT_FOUND', customId);
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of a text input component given a custom id
|
||||||
|
* @param {string} customId The custom id of the text input component
|
||||||
|
* @returns {?string}
|
||||||
|
*/
|
||||||
|
getTextInputValue(customId) {
|
||||||
|
const field = this.getField(customId);
|
||||||
|
const expectedType = MessageComponentTypes[MessageComponentTypes.TEXT_INPUT];
|
||||||
|
if (field.type !== expectedType) {
|
||||||
|
throw new TypeError('MODAL_SUBMIT_INTERACTION_FIELD_TYPE', customId, field.type, expectedType);
|
||||||
|
}
|
||||||
|
return field.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ModalSubmitFieldsResolver;
|
||||||
119
src/structures/ModalSubmitInteraction.js
Normal file
119
src/structures/ModalSubmitInteraction.js
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const Interaction = require('./Interaction');
|
||||||
|
const InteractionWebhook = require('./InteractionWebhook');
|
||||||
|
const ModalSubmitFieldsResolver = require('./ModalSubmitFieldsResolver');
|
||||||
|
const InteractionResponses = require('./interfaces/InteractionResponses');
|
||||||
|
const { MessageComponentTypes } = require('../util/Constants');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a modal submit interaction.
|
||||||
|
* @extends {Interaction}
|
||||||
|
* @implements {InteractionResponses}
|
||||||
|
*/
|
||||||
|
class ModalSubmitInteraction extends Interaction {
|
||||||
|
constructor(client, data) {
|
||||||
|
super(client, data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The custom id of the modal.
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
this.customId = data.data.custom_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} PartialTextInputData
|
||||||
|
* @property {string} [customId] A unique string to be sent in the interaction when submitted
|
||||||
|
* @property {MessageComponentType} [type] The type of this component
|
||||||
|
* @property {string} [value] Value of this text input component
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} PartialModalActionRow
|
||||||
|
* @property {MessageComponentType} [type] The type of this component
|
||||||
|
* @property {PartialTextInputData[]} [components] Partial text input components
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The inputs within the modal
|
||||||
|
* @type {PartialModalActionRow[]}
|
||||||
|
*/
|
||||||
|
this.components =
|
||||||
|
data.data.components?.map(c => ({
|
||||||
|
type: MessageComponentTypes[c.type],
|
||||||
|
components: ModalSubmitInteraction.transformComponent(c),
|
||||||
|
})) ?? [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message associated with this interaction
|
||||||
|
* @type {Message|APIMessage|null}
|
||||||
|
*/
|
||||||
|
this.message = data.message ? this.channel?.messages._add(data.message) ?? data.message : null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The fields within the modal
|
||||||
|
* @type {ModalSubmitFieldsResolver}
|
||||||
|
*/
|
||||||
|
this.fields = new ModalSubmitFieldsResolver(this.components);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the reply to this interaction has been deferred
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
this.deferred = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the reply to this interaction is ephemeral
|
||||||
|
* @type {?boolean}
|
||||||
|
*/
|
||||||
|
this.ephemeral = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this interaction has already been replied to
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
this.replied = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An associated interaction webhook, can be used to further interact with this interaction
|
||||||
|
* @type {InteractionWebhook}
|
||||||
|
*/
|
||||||
|
this.webhook = new InteractionWebhook(this.client, this.applicationId, this.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms component data to discord.js-compatible data
|
||||||
|
* @param {*} rawComponent The data to transform
|
||||||
|
* @returns {PartialTextInputData[]}
|
||||||
|
*/
|
||||||
|
static transformComponent(rawComponent) {
|
||||||
|
return rawComponent.components.map(c => ({
|
||||||
|
value: c.value,
|
||||||
|
type: MessageComponentTypes[c.type],
|
||||||
|
customId: c.custom_id,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this is from a {@link MessageComponentInteraction}.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
isFromMessage() {
|
||||||
|
return Boolean(this.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are here only for documentation purposes - they are implemented by InteractionResponses
|
||||||
|
/* eslint-disable no-empty-function */
|
||||||
|
deferReply() {}
|
||||||
|
reply() {}
|
||||||
|
fetchReply() {}
|
||||||
|
editReply() {}
|
||||||
|
deleteReply() {}
|
||||||
|
followUp() {}
|
||||||
|
update() {}
|
||||||
|
deferUpdate() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
InteractionResponses.applyToClass(ModalSubmitInteraction, ['showModal', 'awaitModalSubmit']);
|
||||||
|
|
||||||
|
module.exports = ModalSubmitInteraction;
|
||||||
@@ -10,7 +10,12 @@ const Util = require('../util/Util');
|
|||||||
* Activity sent in a message.
|
* Activity sent in a message.
|
||||||
* @typedef {Object} MessageActivity
|
* @typedef {Object} MessageActivity
|
||||||
* @property {string} [partyId] Id of the party represented in activity
|
* @property {string} [partyId] Id of the party represented in activity
|
||||||
* @property {number} [type] Type of activity sent
|
* @property {MessageActivityType} type Type of activity sent
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @external MessageActivityType
|
||||||
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v9/enum/MessageActivityType}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -271,7 +276,7 @@ class Activity {
|
|||||||
* Creation date of the activity
|
* Creation date of the activity
|
||||||
* @type {number}
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
this.createdTimestamp = new Date(data.created_at).getTime();
|
this.createdTimestamp = data.created_at;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -351,13 +356,21 @@ class RichPresenceAssets {
|
|||||||
* @returns {?string}
|
* @returns {?string}
|
||||||
*/
|
*/
|
||||||
smallImageURL({ format, size } = {}) {
|
smallImageURL({ format, size } = {}) {
|
||||||
return (
|
if (!this.smallImage) return null;
|
||||||
this.smallImage &&
|
if (this.smallImage.includes(':')) {
|
||||||
this.activity.presence.client.rest.cdn.AppAsset(this.activity.applicationId, this.smallImage, {
|
const [platform, id] = this.smallImage.split(':');
|
||||||
format,
|
switch (platform) {
|
||||||
size,
|
case 'mp':
|
||||||
})
|
return `https://media.discordapp.net/${id}`;
|
||||||
);
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.activity.presence.client.rest.cdn.AppAsset(this.activity.applicationId, this.smallImage, {
|
||||||
|
format,
|
||||||
|
size,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -367,11 +380,20 @@ class RichPresenceAssets {
|
|||||||
*/
|
*/
|
||||||
largeImageURL({ format, size } = {}) {
|
largeImageURL({ format, size } = {}) {
|
||||||
if (!this.largeImage) return null;
|
if (!this.largeImage) return null;
|
||||||
if (/^spotify:/.test(this.largeImage)) {
|
if (this.largeImage.includes(':')) {
|
||||||
return `https://i.scdn.co/image/${this.largeImage.slice(8)}`;
|
const [platform, id] = this.largeImage.split(':');
|
||||||
} else if (/^twitch:/.test(this.largeImage)) {
|
switch (platform) {
|
||||||
return `https://static-cdn.jtvnw.net/previews-ttv/live_user_${this.largeImage.slice(7)}.png`;
|
case 'mp':
|
||||||
|
return `https://media.discordapp.net/${id}`;
|
||||||
|
case 'spotify':
|
||||||
|
return `https://i.scdn.co/image/${id}`;
|
||||||
|
case 'twitch':
|
||||||
|
return `https://static-cdn.jtvnw.net/previews-ttv/live_user_${id}.png`;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.activity.presence.client.rest.cdn.AppAsset(this.activity.applicationId, this.largeImage, {
|
return this.activity.presence.client.rest.cdn.AppAsset(this.activity.applicationId, this.largeImage, {
|
||||||
format,
|
format,
|
||||||
size,
|
size,
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ const Base = require('./Base');
|
|||||||
const { Error } = require('../errors');
|
const { Error } = require('../errors');
|
||||||
const Permissions = require('../util/Permissions');
|
const Permissions = require('../util/Permissions');
|
||||||
const SnowflakeUtil = require('../util/SnowflakeUtil');
|
const SnowflakeUtil = require('../util/SnowflakeUtil');
|
||||||
const Util = require('../util/Util');
|
|
||||||
|
|
||||||
let deprecationEmittedForComparePositions = false;
|
let deprecationEmittedForComparePositions = false;
|
||||||
|
|
||||||
@@ -399,20 +398,8 @@ class Role extends Base {
|
|||||||
* .then(updated => console.log(`Role position: ${updated.position}`))
|
* .then(updated => console.log(`Role position: ${updated.position}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
async setPosition(position, { relative, reason } = {}) {
|
setPosition(position, options = {}) {
|
||||||
const updatedRoles = await Util.setPosition(
|
return this.guild.roles.setPosition(this, position, options);
|
||||||
this,
|
|
||||||
position,
|
|
||||||
relative,
|
|
||||||
this.guild._sortedRoles(),
|
|
||||||
this.client.api.guilds(this.guild.id).roles,
|
|
||||||
reason,
|
|
||||||
);
|
|
||||||
this.client.actions.GuildRolesPositionUpdate.handle({
|
|
||||||
guild_id: this.guild.id,
|
|
||||||
roles: updatedRoles,
|
|
||||||
});
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -55,14 +55,15 @@ class StageChannel extends BaseGuildVoiceChannel {
|
|||||||
/**
|
/**
|
||||||
* Sets the RTC region of the channel.
|
* Sets the RTC region of the channel.
|
||||||
* @name StageChannel#setRTCRegion
|
* @name StageChannel#setRTCRegion
|
||||||
* @param {?string} region The new region of the channel. Set to `null` to remove a specific region for the channel
|
* @param {?string} rtcRegion The new region of the channel. Set to `null` to remove a specific region for the channel
|
||||||
|
* @param {string} [reason] The reason for modifying this region.
|
||||||
* @returns {Promise<StageChannel>}
|
* @returns {Promise<StageChannel>}
|
||||||
* @example
|
* @example
|
||||||
* // Set the RTC region to europe
|
* // Set the RTC region to sydney
|
||||||
* stageChannel.setRTCRegion('europe');
|
* stageChannel.setRTCRegion('sydney');
|
||||||
* @example
|
* @example
|
||||||
* // Remove a fixed region for this channel - let Discord decide automatically
|
* // Remove a fixed region for this channel - let Discord decide automatically
|
||||||
* stageChannel.setRTCRegion(null);
|
* stageChannel.setRTCRegion(null, 'We want to let Discord decide.');
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,16 @@ class StageInstance extends Base {
|
|||||||
} else {
|
} else {
|
||||||
this.discoverableDisabled ??= null;
|
this.discoverableDisabled ??= null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('guild_scheduled_event_id' in data) {
|
||||||
|
/**
|
||||||
|
* The associated guild scheduled event id of this stage instance
|
||||||
|
* @type {?Snowflake}
|
||||||
|
*/
|
||||||
|
this.guildScheduledEventId = data.guild_scheduled_event_id;
|
||||||
|
} else {
|
||||||
|
this.guildScheduledEventId ??= null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,6 +93,15 @@ class StageInstance extends Base {
|
|||||||
return this.client.channels.resolve(this.channelId);
|
return this.client.channels.resolve(this.channelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The associated guild scheduled event of this stage instance
|
||||||
|
* @type {?GuildScheduledEvent}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get guildScheduledEvent() {
|
||||||
|
return this.guild?.scheduledEvents.resolve(this.guildScheduledEventId) ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the stage instance has been deleted
|
* Whether or not the stage instance has been deleted
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
|
|||||||
@@ -228,10 +228,7 @@ class Sticker extends Base {
|
|||||||
async fetchUser() {
|
async fetchUser() {
|
||||||
if (this.partial) await this.fetch();
|
if (this.partial) await this.fetch();
|
||||||
if (!this.guildId) throw new Error('NOT_GUILD_STICKER');
|
if (!this.guildId) throw new Error('NOT_GUILD_STICKER');
|
||||||
|
return this.guild.stickers.fetchUser(this);
|
||||||
const data = await this.client.api.guilds(this.guildId).stickers(this.id).get();
|
|
||||||
this._patch(data);
|
|
||||||
return this.user;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const GuildChannel = require('./GuildChannel');
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a guild store channel on Discord.
|
* Represents a guild store channel on Discord.
|
||||||
* <warn>Store channels are deprecated and will be removed from Discord in March 2022. See
|
* <warn>Store channels have been removed from Discord. See
|
||||||
* [Self-serve Game Selling Deprecation](https://support-dev.discord.com/hc/en-us/articles/4414590563479)
|
* [Self-serve Game Selling Deprecation](https://support-dev.discord.com/hc/en-us/articles/4414590563479)
|
||||||
* for more information.</warn>
|
* for more information.</warn>
|
||||||
* @extends {GuildChannel}
|
* @extends {GuildChannel}
|
||||||
|
|||||||
201
src/structures/TextInputComponent.js
Normal file
201
src/structures/TextInputComponent.js
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const BaseMessageComponent = require('./BaseMessageComponent');
|
||||||
|
const { RangeError } = require('../errors');
|
||||||
|
const { TextInputStyles, MessageComponentTypes } = require('../util/Constants');
|
||||||
|
const Util = require('../util/Util');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a text input component in a modal
|
||||||
|
* @extends {BaseMessageComponent}
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TextInputComponent extends BaseMessageComponent {
|
||||||
|
/**
|
||||||
|
* @typedef {BaseMessageComponentOptions} TextInputComponentOptions
|
||||||
|
* @property {string} [customId] A unique string to be sent in the interaction when submitted
|
||||||
|
* @property {string} [label] The text to be displayed above this text input component
|
||||||
|
* @property {number} [maxLength] Maximum length of text that can be entered
|
||||||
|
* @property {number} [minLength] Minimum length of text required to be entered
|
||||||
|
* @property {string} [placeholder] Custom placeholder text to display when no text is entered
|
||||||
|
* @property {boolean} [required] Whether or not this text input component is required
|
||||||
|
* @property {TextInputStyleResolvable} [style] The style of this text input component
|
||||||
|
* @property {string} [value] Value of this text input component
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {TextInputComponent|TextInputComponentOptions} [data={}] TextInputComponent to clone or raw data
|
||||||
|
*/
|
||||||
|
constructor(data = {}) {
|
||||||
|
super({ type: 'TEXT_INPUT' });
|
||||||
|
|
||||||
|
this.setup(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
setup(data) {
|
||||||
|
/**
|
||||||
|
* A unique string to be sent in the interaction when submitted
|
||||||
|
* @type {?string}
|
||||||
|
*/
|
||||||
|
this.customId = data.custom_id ?? data.customId ?? null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The text to be displayed above this text input component
|
||||||
|
* @type {?string}
|
||||||
|
*/
|
||||||
|
this.label = data.label ?? null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum length of text that can be entered
|
||||||
|
* @type {?number}
|
||||||
|
*/
|
||||||
|
this.maxLength = data.max_length ?? data.maxLength ?? null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimum length of text required to be entered
|
||||||
|
* @type {?string}
|
||||||
|
*/
|
||||||
|
this.minLength = data.min_length ?? data.minLength ?? null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom placeholder text to display when no text is entered
|
||||||
|
* @type {?string}
|
||||||
|
*/
|
||||||
|
this.placeholder = data.placeholder ?? null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not this text input component is required
|
||||||
|
* @type {?boolean}
|
||||||
|
*/
|
||||||
|
this.required = data.required ?? false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The style of this text input component
|
||||||
|
* @type {?TextInputStyle}
|
||||||
|
*/
|
||||||
|
this.style = data.style ? TextInputComponent.resolveStyle(data.style) : null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Value of this text input component
|
||||||
|
* @type {?string}
|
||||||
|
*/
|
||||||
|
this.value = data.value ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the custom id of this text input component
|
||||||
|
* @param {string} customId A unique string to be sent in the interaction when submitted
|
||||||
|
* @returns {TextInputComponent}
|
||||||
|
*/
|
||||||
|
setCustomId(customId) {
|
||||||
|
this.customId = Util.verifyString(customId, RangeError, 'TEXT_INPUT_CUSTOM_ID');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the label of this text input component
|
||||||
|
* @param {string} label The text to be displayed above this text input component
|
||||||
|
* @returns {TextInputComponent}
|
||||||
|
*/
|
||||||
|
setLabel(label) {
|
||||||
|
this.label = Util.verifyString(label, RangeError, 'TEXT_INPUT_LABEL');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the text input component to be required for modal submission
|
||||||
|
* @param {boolean} [required=true] Whether this text input component is required
|
||||||
|
* @returns {TextInputComponent}
|
||||||
|
*/
|
||||||
|
setRequired(required = true) {
|
||||||
|
this.required = required;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum length of text input required in this text input component
|
||||||
|
* @param {number} maxLength Maximum length of text to be required
|
||||||
|
* @returns {TextInputComponent}
|
||||||
|
*/
|
||||||
|
setMaxLength(maxLength) {
|
||||||
|
this.maxLength = maxLength;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the minimum length of text input required in this text input component
|
||||||
|
* @param {number} minLength Minimum length of text to be required
|
||||||
|
* @returns {TextInputComponent}
|
||||||
|
*/
|
||||||
|
setMinLength(minLength) {
|
||||||
|
this.minLength = minLength;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the placeholder of this text input component
|
||||||
|
* @param {string} placeholder Custom placeholder text to display when no text is entered
|
||||||
|
* @returns {TextInputComponent}
|
||||||
|
*/
|
||||||
|
setPlaceholder(placeholder) {
|
||||||
|
this.placeholder = Util.verifyString(placeholder, RangeError, 'TEXT_INPUT_PLACEHOLDER');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the style of this text input component
|
||||||
|
* @param {TextInputStyleResolvable} style The style of this text input component
|
||||||
|
* @returns {TextInputComponent}
|
||||||
|
*/
|
||||||
|
setStyle(style) {
|
||||||
|
this.style = TextInputComponent.resolveStyle(style);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of this text input component
|
||||||
|
* @param {string} value Value of this text input component
|
||||||
|
* @returns {TextInputComponent}
|
||||||
|
*/
|
||||||
|
setValue(value) {
|
||||||
|
this.value = Util.verifyString(value, RangeError, 'TEXT_INPUT_VALUE');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms the text input component into a plain object
|
||||||
|
* @returns {APITextInput} The raw data of this text input component
|
||||||
|
*/
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
custom_id: this.customId,
|
||||||
|
label: this.label,
|
||||||
|
max_length: this.maxLength,
|
||||||
|
min_length: this.minLength,
|
||||||
|
placeholder: this.placeholder,
|
||||||
|
required: this.required,
|
||||||
|
style: TextInputStyles[this.style],
|
||||||
|
type: MessageComponentTypes[this.type],
|
||||||
|
value: this.value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data that can be resolved to a TextInputStyle. This can be
|
||||||
|
* * TextInputStyle
|
||||||
|
* * number
|
||||||
|
* @typedef {number|TextInputStyle} TextInputStyleResolvable
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves the style of a text input component
|
||||||
|
* @param {TextInputStyleResolvable} style The style to resolve
|
||||||
|
* @returns {TextInputStyle}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static resolveStyle(style) {
|
||||||
|
return typeof style === 'string' ? style : TextInputStyles[style];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TextInputComponent;
|
||||||
@@ -6,6 +6,7 @@ const { RangeError } = require('../errors');
|
|||||||
const MessageManager = require('../managers/MessageManager');
|
const MessageManager = require('../managers/MessageManager');
|
||||||
const ThreadMemberManager = require('../managers/ThreadMemberManager');
|
const ThreadMemberManager = require('../managers/ThreadMemberManager');
|
||||||
const Permissions = require('../util/Permissions');
|
const Permissions = require('../util/Permissions');
|
||||||
|
const { resolveAutoArchiveMaxLimit } = require('../util/Util');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a thread channel on Discord.
|
* Represents a thread channel on Discord.
|
||||||
@@ -100,6 +101,11 @@ class ThreadChannel extends Channel {
|
|||||||
* @type {?number}
|
* @type {?number}
|
||||||
*/
|
*/
|
||||||
this.archiveTimestamp = new Date(data.thread_metadata.archive_timestamp).getTime();
|
this.archiveTimestamp = new Date(data.thread_metadata.archive_timestamp).getTime();
|
||||||
|
|
||||||
|
if ('create_timestamp' in data.thread_metadata) {
|
||||||
|
// Note: this is needed because we can't assign directly to getters
|
||||||
|
this._createdTimestamp = Date.parse(data.thread_metadata.create_timestamp);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.locked ??= null;
|
this.locked ??= null;
|
||||||
this.archived ??= null;
|
this.archived ??= null;
|
||||||
@@ -108,6 +114,8 @@ class ThreadChannel extends Channel {
|
|||||||
this.invitable ??= null;
|
this.invitable ??= null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._createdTimestamp ??= this.type === 'GUILD_PRIVATE_THREAD' ? super.createdTimestamp : null;
|
||||||
|
|
||||||
if ('owner_id' in data) {
|
if ('owner_id' in data) {
|
||||||
/**
|
/**
|
||||||
* The id of the member who created this thread
|
* The id of the member who created this thread
|
||||||
@@ -176,6 +184,16 @@ class ThreadChannel extends Channel {
|
|||||||
if (data.messages) for (const message of data.messages) this.messages._add(message);
|
if (data.messages) for (const message of data.messages) this.messages._add(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The timestamp when this thread was created. This isn't available for threads
|
||||||
|
* created before 2022-01-09
|
||||||
|
* @type {?number}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get createdTimestamp() {
|
||||||
|
return this._createdTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A collection of associated guild member objects of this thread's members
|
* A collection of associated guild member objects of this thread's members
|
||||||
* @type {Collection<Snowflake, GuildMember>}
|
* @type {Collection<Snowflake, GuildMember>}
|
||||||
@@ -196,6 +214,15 @@ class ThreadChannel extends Channel {
|
|||||||
return new Date(this.archiveTimestamp);
|
return new Date(this.archiveTimestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time the thread was created at
|
||||||
|
* @type {?Date}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get createdAt() {
|
||||||
|
return this.createdTimestamp && new Date(this.createdTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The parent channel of this thread
|
* The parent channel of this thread
|
||||||
* @type {?(NewsChannel|TextChannel)}
|
* @type {?(NewsChannel|TextChannel)}
|
||||||
@@ -256,10 +283,11 @@ class ThreadChannel extends Channel {
|
|||||||
* <info>This only works when the thread started from a message in the parent channel, otherwise the promise will
|
* <info>This only works when the thread started from a message in the parent channel, otherwise the promise will
|
||||||
* reject. If you just need the id of that message, use {@link ThreadChannel#id} instead.</info>
|
* reject. If you just need the id of that message, use {@link ThreadChannel#id} instead.</info>
|
||||||
* @param {BaseFetchOptions} [options] Additional options for this fetch
|
* @param {BaseFetchOptions} [options] Additional options for this fetch
|
||||||
* @returns {Promise<Message>}
|
* @returns {Promise<Message|null>}
|
||||||
*/
|
*/
|
||||||
fetchStarterMessage(options) {
|
// eslint-disable-next-line require-await
|
||||||
return this.parent.messages.fetch(this.id, options);
|
async fetchStarterMessage(options) {
|
||||||
|
return this.parent?.messages.fetch(this.id, options) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -288,14 +316,8 @@ class ThreadChannel extends Channel {
|
|||||||
*/
|
*/
|
||||||
async edit(data, reason) {
|
async edit(data, reason) {
|
||||||
let autoArchiveDuration = data.autoArchiveDuration;
|
let autoArchiveDuration = data.autoArchiveDuration;
|
||||||
if (data.autoArchiveDuration === 'MAX') {
|
if (autoArchiveDuration === 'MAX') autoArchiveDuration = resolveAutoArchiveMaxLimit(this.guild);
|
||||||
autoArchiveDuration = 1440;
|
|
||||||
if (this.guild.features.includes('SEVEN_DAY_THREAD_ARCHIVE')) {
|
|
||||||
autoArchiveDuration = 10080;
|
|
||||||
} else if (this.guild.features.includes('THREE_DAY_THREAD_ARCHIVE')) {
|
|
||||||
autoArchiveDuration = 4320;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const newData = await this.client.api.channels(this.id).patch({
|
const newData = await this.client.api.channels(this.id).patch({
|
||||||
data: {
|
data: {
|
||||||
name: (data.name ?? this.name).trim(),
|
name: (data.name ?? this.name).trim(),
|
||||||
@@ -487,7 +509,15 @@ class ThreadChannel extends Channel {
|
|||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
get unarchivable() {
|
get unarchivable() {
|
||||||
return this.archived && (this.locked ? this.manageable : this.sendable);
|
return this.archived && this.sendable && (!this.locked || this.manageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this thread is a private thread
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
isPrivate() {
|
||||||
|
return this.type === 'GUILD_PRIVATE_THREAD';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -501,7 +531,7 @@ class ThreadChannel extends Channel {
|
|||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
async delete(reason) {
|
async delete(reason) {
|
||||||
await this.client.api.channels(this.id).delete({ reason });
|
await this.guild.channels.delete(this.id, reason);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,8 +546,10 @@ class ThreadChannel extends Channel {
|
|||||||
createMessageComponentCollector() {}
|
createMessageComponentCollector() {}
|
||||||
awaitMessageComponent() {}
|
awaitMessageComponent() {}
|
||||||
bulkDelete() {}
|
bulkDelete() {}
|
||||||
|
// Doesn't work on Thread channels; setRateLimitPerUser() {}
|
||||||
|
// Doesn't work on Thread channels; setNSFW() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextBasedChannel.applyToClass(ThreadChannel, true);
|
TextBasedChannel.applyToClass(ThreadChannel, true, ['fetchWebhooks', 'setRateLimitPerUser', 'setNSFW']);
|
||||||
|
|
||||||
module.exports = ThreadChannel;
|
module.exports = ThreadChannel;
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
const process = require('node:process');
|
const process = require('node:process');
|
||||||
const BaseGuildVoiceChannel = require('./BaseGuildVoiceChannel');
|
const BaseGuildVoiceChannel = require('./BaseGuildVoiceChannel');
|
||||||
|
const TextBasedChannel = require('./interfaces/TextBasedChannel');
|
||||||
|
const MessageManager = require('../managers/MessageManager');
|
||||||
|
const { VideoQualityModes } = require('../util/Constants');
|
||||||
const Permissions = require('../util/Permissions');
|
const Permissions = require('../util/Permissions');
|
||||||
|
|
||||||
let deprecationEmittedForEditable = false;
|
let deprecationEmittedForEditable = false;
|
||||||
@@ -9,8 +12,65 @@ let deprecationEmittedForEditable = false;
|
|||||||
/**
|
/**
|
||||||
* Represents a guild voice channel on Discord.
|
* Represents a guild voice channel on Discord.
|
||||||
* @extends {BaseGuildVoiceChannel}
|
* @extends {BaseGuildVoiceChannel}
|
||||||
|
* @implements {TextBasedChannel}
|
||||||
*/
|
*/
|
||||||
class VoiceChannel extends BaseGuildVoiceChannel {
|
class VoiceChannel extends BaseGuildVoiceChannel {
|
||||||
|
constructor(guild, data, client) {
|
||||||
|
super(guild, data, client, false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A manager of the messages sent to this channel
|
||||||
|
* @type {MessageManager}
|
||||||
|
*/
|
||||||
|
this.messages = new MessageManager(this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the guild considers this channel NSFW
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
this.nsfw = Boolean(data.nsfw);
|
||||||
|
|
||||||
|
this._patch(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
_patch(data) {
|
||||||
|
super._patch(data);
|
||||||
|
|
||||||
|
if ('video_quality_mode' in data) {
|
||||||
|
/**
|
||||||
|
* The camera video quality mode of the channel.
|
||||||
|
* @type {?VideoQualityMode}
|
||||||
|
*/
|
||||||
|
this.videoQualityMode = VideoQualityModes[data.video_quality_mode];
|
||||||
|
} else {
|
||||||
|
this.videoQualityMode ??= null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('last_message_id' in data) {
|
||||||
|
/**
|
||||||
|
* The last message id sent in the channel, if one was sent
|
||||||
|
* @type {?Snowflake}
|
||||||
|
*/
|
||||||
|
this.lastMessageId = data.last_message_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('messages' in data) {
|
||||||
|
for (const message of data.messages) this.messages._add(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('rate_limit_per_user' in data) {
|
||||||
|
/**
|
||||||
|
* The rate limit per user (slowmode) for this channel in seconds
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
this.rateLimitPerUser = data.rate_limit_per_user;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('nsfw' in data) {
|
||||||
|
this.nsfw = data.nsfw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the channel is editable by the client user
|
* Whether the channel is editable by the client user
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
@@ -87,18 +147,46 @@ class VoiceChannel extends BaseGuildVoiceChannel {
|
|||||||
return this.edit({ userLimit }, reason);
|
return this.edit({ userLimit }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the camera video quality mode of the channel.
|
||||||
|
* @param {VideoQualityMode|number} videoQualityMode The new camera video quality mode.
|
||||||
|
* @param {string} [reason] Reason for changing the camera video quality mode.
|
||||||
|
* @returns {Promise<VoiceChannel>}
|
||||||
|
*/
|
||||||
|
setVideoQualityMode(videoQualityMode, reason) {
|
||||||
|
return this.edit({ videoQualityMode }, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are here only for documentation purposes - they are implemented by TextBasedChannel
|
||||||
|
/* eslint-disable no-empty-function */
|
||||||
|
get lastMessage() {}
|
||||||
|
send() {}
|
||||||
|
sendTyping() {}
|
||||||
|
createMessageCollector() {}
|
||||||
|
awaitMessages() {}
|
||||||
|
createMessageComponentCollector() {}
|
||||||
|
awaitMessageComponent() {}
|
||||||
|
bulkDelete() {}
|
||||||
|
fetchWebhooks() {}
|
||||||
|
createWebhook() {}
|
||||||
|
setRateLimitPerUser() {}
|
||||||
|
setNSFW() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the RTC region of the channel.
|
* Sets the RTC region of the channel.
|
||||||
* @name VoiceChannel#setRTCRegion
|
* @name VoiceChannel#setRTCRegion
|
||||||
* @param {?string} region The new region of the channel. Set to `null` to remove a specific region for the channel
|
* @param {?string} rtcRegion The new region of the channel. Set to `null` to remove a specific region for the channel
|
||||||
|
* @param {string} [reason] The reason for modifying this region.
|
||||||
* @returns {Promise<VoiceChannel>}
|
* @returns {Promise<VoiceChannel>}
|
||||||
* @example
|
* @example
|
||||||
* // Set the RTC region to europe
|
* // Set the RTC region to sydney
|
||||||
* voiceChannel.setRTCRegion('europe');
|
* voiceChannel.setRTCRegion('sydney');
|
||||||
* @example
|
* @example
|
||||||
* // Remove a fixed region for this channel - let Discord decide automatically
|
* // Remove a fixed region for this channel - let Discord decide automatically
|
||||||
* voiceChannel.setRTCRegion(null);
|
* voiceChannel.setRTCRegion(null, 'We want to let Discord decide.');
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextBasedChannel.applyToClass(VoiceChannel, true, ['lastPinAt']);
|
||||||
|
|
||||||
module.exports = VoiceChannel;
|
module.exports = VoiceChannel;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class VoiceRegion {
|
|||||||
/**
|
/**
|
||||||
* Whether the region is VIP-only
|
* Whether the region is VIP-only
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
|
* @deprecated This property is no longer being sent by the API.
|
||||||
*/
|
*/
|
||||||
this.vip = data.vip;
|
this.vip = data.vip;
|
||||||
|
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ class VoiceState extends Base {
|
|||||||
* The time at which the member requested to speak. This property is specific to stage channels only.
|
* The time at which the member requested to speak. This property is specific to stage channels only.
|
||||||
* @type {?number}
|
* @type {?number}
|
||||||
*/
|
*/
|
||||||
this.requestToSpeakTimestamp = new Date(data.request_to_speak_timestamp).getTime();
|
this.requestToSpeakTimestamp = data.request_to_speak_timestamp && Date.parse(data.request_to_speak_timestamp);
|
||||||
} else {
|
} else {
|
||||||
this.requestToSpeakTimestamp ??= null;
|
this.requestToSpeakTimestamp ??= null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ class Webhook {
|
|||||||
* @property {string} [avatarURL] Avatar URL override for the message
|
* @property {string} [avatarURL] Avatar URL override for the message
|
||||||
* @property {Snowflake} [threadId] The id of the thread in the channel to send to.
|
* @property {Snowflake} [threadId] The id of the thread in the channel to send to.
|
||||||
* <info>For interaction webhooks, this property is ignored</info>
|
* <info>For interaction webhooks, this property is ignored</info>
|
||||||
|
* @property {MessageFlags} [flags] Which flags to set for the message. Only `SUPPRESS_EMBEDS` can be set.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const process = require('node:process');
|
||||||
const { ClientApplicationAssetTypes, Endpoints } = require('../../util/Constants');
|
const { ClientApplicationAssetTypes, Endpoints } = require('../../util/Constants');
|
||||||
const SnowflakeUtil = require('../../util/SnowflakeUtil');
|
const SnowflakeUtil = require('../../util/SnowflakeUtil');
|
||||||
const Base = require('../Base');
|
const Base = require('../Base');
|
||||||
|
|
||||||
const AssetTypes = Object.keys(ClientApplicationAssetTypes);
|
const AssetTypes = Object.keys(ClientApplicationAssetTypes);
|
||||||
|
|
||||||
|
let deprecationEmittedForFetchAssets = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an OAuth2 Application.
|
* Represents an OAuth2 Application.
|
||||||
* @abstract
|
* @abstract
|
||||||
@@ -103,8 +106,18 @@ class Application extends Base {
|
|||||||
/**
|
/**
|
||||||
* Gets the application's rich presence assets.
|
* Gets the application's rich presence assets.
|
||||||
* @returns {Promise<Array<ApplicationAsset>>}
|
* @returns {Promise<Array<ApplicationAsset>>}
|
||||||
|
* @deprecated This will be removed in the next major as it is unsupported functionality.
|
||||||
*/
|
*/
|
||||||
async fetchAssets() {
|
async fetchAssets() {
|
||||||
|
if (!deprecationEmittedForFetchAssets) {
|
||||||
|
process.emitWarning(
|
||||||
|
'Application#fetchAssets is deprecated as it is unsupported and will be removed in the next major version.',
|
||||||
|
'DeprecationWarning',
|
||||||
|
);
|
||||||
|
|
||||||
|
deprecationEmittedForFetchAssets = true;
|
||||||
|
}
|
||||||
|
|
||||||
const assets = await this.client.api.oauth2.applications(this.id).assets.get();
|
const assets = await this.client.api.oauth2.applications(this.id).assets.get();
|
||||||
return assets.map(a => ({
|
return assets.map(a => ({
|
||||||
id: a.id,
|
id: a.id,
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { Error } = require('../../errors');
|
const { Error } = require('../../errors');
|
||||||
const { InteractionResponseTypes } = require('../../util/Constants');
|
const { InteractionResponseTypes, InteractionTypes } = require('../../util/Constants');
|
||||||
const MessageFlags = require('../../util/MessageFlags');
|
const MessageFlags = require('../../util/MessageFlags');
|
||||||
|
const InteractionCollector = require('../InteractionCollector');
|
||||||
const MessagePayload = require('../MessagePayload');
|
const MessagePayload = require('../MessagePayload');
|
||||||
|
const Modal = require('../Modal');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for classes that support shared interaction response types.
|
* Interface for classes that support shared interaction response types.
|
||||||
@@ -28,6 +30,8 @@ class InteractionResponses {
|
|||||||
* @typedef {BaseMessageOptions} InteractionReplyOptions
|
* @typedef {BaseMessageOptions} InteractionReplyOptions
|
||||||
* @property {boolean} [ephemeral] Whether the reply should be ephemeral
|
* @property {boolean} [ephemeral] Whether the reply should be ephemeral
|
||||||
* @property {boolean} [fetchReply] Whether to fetch the reply
|
* @property {boolean} [fetchReply] Whether to fetch the reply
|
||||||
|
* @property {MessageFlags} [flags] Which flags to set for the message.
|
||||||
|
* Only `SUPPRESS_EMBEDS` and `EPHEMERAL` can be set.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -224,6 +228,56 @@ class InteractionResponses {
|
|||||||
return options.fetchReply ? this.fetchReply() : undefined;
|
return options.fetchReply ? this.fetchReply() : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a modal component
|
||||||
|
* @param {Modal|ModalOptions} modal The modal to show
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async showModal(modal) {
|
||||||
|
if (this.deferred || this.replied) throw new Error('INTERACTION_ALREADY_REPLIED');
|
||||||
|
|
||||||
|
const _modal = modal instanceof Modal ? modal : new Modal(modal);
|
||||||
|
await this.client.api.interactions(this.id, this.token).callback.post({
|
||||||
|
data: {
|
||||||
|
type: InteractionResponseTypes.MODAL,
|
||||||
|
data: _modal.toJSON(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.replied = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object containing the same properties as CollectorOptions, but a few more:
|
||||||
|
* @typedef {Object} AwaitModalSubmitOptions
|
||||||
|
* @property {CollectorFilter} [filter] The filter applied to this collector
|
||||||
|
* @property {number} time Time to wait for an interaction before rejecting
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects a single modal submit interaction that passes the filter.
|
||||||
|
* The Promise will reject if the time expires.
|
||||||
|
* @param {AwaitModalSubmitOptions} options Options to pass to the internal collector
|
||||||
|
* @returns {Promise<ModalSubmitInteraction>}
|
||||||
|
* @example
|
||||||
|
* // Collect a modal submit interaction
|
||||||
|
* const filter = (interaction) => interaction.customId === 'modal';
|
||||||
|
* interaction.awaitModalSubmit({ filter, time: 15_000 })
|
||||||
|
* .then(interaction => console.log(`${interaction.customId} was submitted!`))
|
||||||
|
* .catch(console.error);
|
||||||
|
*/
|
||||||
|
awaitModalSubmit(options) {
|
||||||
|
if (typeof options.time !== 'number') throw new Error('INVALID_TYPE', 'time', 'number');
|
||||||
|
const _options = { ...options, max: 1, interactionType: InteractionTypes.MODAL_SUBMIT };
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const collector = new InteractionCollector(this.client, _options);
|
||||||
|
collector.once('end', (interactions, reason) => {
|
||||||
|
const interaction = interactions.first();
|
||||||
|
if (interaction) resolve(interaction);
|
||||||
|
else reject(new Error('INTERACTION_COLLECTOR_ERROR', reason));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static applyToClass(structure, ignore = []) {
|
static applyToClass(structure, ignore = []) {
|
||||||
const props = [
|
const props = [
|
||||||
'deferReply',
|
'deferReply',
|
||||||
@@ -234,6 +288,8 @@ class InteractionResponses {
|
|||||||
'followUp',
|
'followUp',
|
||||||
'deferUpdate',
|
'deferUpdate',
|
||||||
'update',
|
'update',
|
||||||
|
'showModal',
|
||||||
|
'awaitModalSubmit',
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const prop of props) {
|
for (const prop of props) {
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ class TextBasedChannel {
|
|||||||
* @typedef {BaseMessageOptions} MessageOptions
|
* @typedef {BaseMessageOptions} MessageOptions
|
||||||
* @property {ReplyOptions} [reply] The options for replying to a message
|
* @property {ReplyOptions} [reply] The options for replying to a message
|
||||||
* @property {StickerResolvable[]} [stickers=[]] Stickers to send in the message
|
* @property {StickerResolvable[]} [stickers=[]] Stickers to send in the message
|
||||||
|
* @property {MessageFlags} [flags] Which flags to set for the message. Only `SUPPRESS_EMBEDS` can be set.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,7 +129,7 @@ class TextBasedChannel {
|
|||||||
* channel.send({
|
* channel.send({
|
||||||
* files: [{
|
* files: [{
|
||||||
* attachment: 'entire/path/to/file.jpg',
|
* attachment: 'entire/path/to/file.jpg',
|
||||||
* name: 'file.jpg'
|
* name: 'file.jpg',
|
||||||
* description: 'A description of the file'
|
* description: 'A description of the file'
|
||||||
* }]
|
* }]
|
||||||
* })
|
* })
|
||||||
@@ -147,7 +148,7 @@ class TextBasedChannel {
|
|||||||
* ],
|
* ],
|
||||||
* files: [{
|
* files: [{
|
||||||
* attachment: 'entire/path/to/file.jpg',
|
* attachment: 'entire/path/to/file.jpg',
|
||||||
* name: 'file.jpg'
|
* name: 'file.jpg',
|
||||||
* description: 'A description of the file'
|
* description: 'A description of the file'
|
||||||
* }]
|
* }]
|
||||||
* })
|
* })
|
||||||
@@ -236,7 +237,7 @@ class TextBasedChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a button interaction collector.
|
* Creates a component interaction collector.
|
||||||
* @param {MessageComponentCollectorOptions} [options={}] Options to send to the collector
|
* @param {MessageComponentCollectorOptions} [options={}] Options to send to the collector
|
||||||
* @returns {InteractionCollector}
|
* @returns {InteractionCollector}
|
||||||
* @example
|
* @example
|
||||||
@@ -283,7 +284,7 @@ class TextBasedChannel {
|
|||||||
* @param {Collection<Snowflake, Message>|MessageResolvable[]|number} messages
|
* @param {Collection<Snowflake, Message>|MessageResolvable[]|number} messages
|
||||||
* Messages or number of messages to delete
|
* Messages or number of messages to delete
|
||||||
* @param {boolean} [filterOld=false] Filter messages to remove those which are older than two weeks automatically
|
* @param {boolean} [filterOld=false] Filter messages to remove those which are older than two weeks automatically
|
||||||
* @returns {Promise<Collection<Snowflake, Message>>} Returns the deleted messages
|
* @returns {Promise<Collection<Snowflake, Message|undefined>>} Returns the deleted messages
|
||||||
* @example
|
* @example
|
||||||
* // Bulk delete messages
|
* // Bulk delete messages
|
||||||
* channel.bulkDelete(5)
|
* channel.bulkDelete(5)
|
||||||
@@ -329,6 +330,64 @@ class TextBasedChannel {
|
|||||||
throw new TypeError('MESSAGE_BULK_DELETE_TYPE');
|
throw new TypeError('MESSAGE_BULK_DELETE_TYPE');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches all webhooks for the channel.
|
||||||
|
* @returns {Promise<Collection<Snowflake, Webhook>>}
|
||||||
|
* @example
|
||||||
|
* // Fetch webhooks
|
||||||
|
* channel.fetchWebhooks()
|
||||||
|
* .then(hooks => console.log(`This channel has ${hooks.size} hooks`))
|
||||||
|
* .catch(console.error);
|
||||||
|
*/
|
||||||
|
fetchWebhooks() {
|
||||||
|
return this.guild.channels.fetchWebhooks(this.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options used to create a {@link Webhook} in a guild text-based channel.
|
||||||
|
* @typedef {Object} ChannelWebhookCreateOptions
|
||||||
|
* @property {?(BufferResolvable|Base64Resolvable)} [avatar] Avatar for the webhook
|
||||||
|
* @property {string} [reason] Reason for creating the webhook
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a webhook for the channel.
|
||||||
|
* @param {string} name The name of the webhook
|
||||||
|
* @param {ChannelWebhookCreateOptions} [options] Options for creating the webhook
|
||||||
|
* @returns {Promise<Webhook>} Returns the created Webhook
|
||||||
|
* @example
|
||||||
|
* // Create a webhook for the current channel
|
||||||
|
* channel.createWebhook('Snek', {
|
||||||
|
* avatar: 'https://i.imgur.com/mI8XcpG.jpg',
|
||||||
|
* reason: 'Needed a cool new Webhook'
|
||||||
|
* })
|
||||||
|
* .then(console.log)
|
||||||
|
* .catch(console.error)
|
||||||
|
*/
|
||||||
|
createWebhook(name, options = {}) {
|
||||||
|
return this.guild.channels.createWebhook(this.id, name, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the rate limit per user (slowmode) for this channel.
|
||||||
|
* @param {number} rateLimitPerUser The new rate limit in seconds
|
||||||
|
* @param {string} [reason] Reason for changing the channel's rate limit
|
||||||
|
* @returns {Promise<this>}
|
||||||
|
*/
|
||||||
|
setRateLimitPerUser(rateLimitPerUser, reason) {
|
||||||
|
return this.edit({ rateLimitPerUser }, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether this channel is flagged as NSFW.
|
||||||
|
* @param {boolean} [nsfw=true] Whether the channel should be considered NSFW
|
||||||
|
* @param {string} [reason] Reason for changing the channel's NSFW flag
|
||||||
|
* @returns {Promise<this>}
|
||||||
|
*/
|
||||||
|
setNSFW(nsfw = true, reason) {
|
||||||
|
return this.edit({ nsfw }, reason);
|
||||||
|
}
|
||||||
|
|
||||||
static applyToClass(structure, full = false, ignore = []) {
|
static applyToClass(structure, full = false, ignore = []) {
|
||||||
const props = ['send'];
|
const props = ['send'];
|
||||||
if (full) {
|
if (full) {
|
||||||
@@ -341,6 +400,10 @@ class TextBasedChannel {
|
|||||||
'awaitMessages',
|
'awaitMessages',
|
||||||
'createMessageComponentCollector',
|
'createMessageComponentCollector',
|
||||||
'awaitMessageComponent',
|
'awaitMessageComponent',
|
||||||
|
'fetchWebhooks',
|
||||||
|
'createWebhook',
|
||||||
|
'setRateLimitPerUser',
|
||||||
|
'setNSFW',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
for (const prop of props) {
|
for (const prop of props) {
|
||||||
|
|||||||
@@ -6,8 +6,20 @@ const { Error, RangeError, TypeError } = require('../errors');
|
|||||||
|
|
||||||
exports.UserAgent = `DiscordBot (${Package.homepage}, ${Package.version}) Node.js/${process.version}`;
|
exports.UserAgent = `DiscordBot (${Package.homepage}, ${Package.version}) Node.js/${process.version}`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The types of WebSocket error codes:
|
||||||
|
* * 1000: WS_CLOSE_REQUESTED
|
||||||
|
* * 1011: INTERNAL_ERROR
|
||||||
|
* * 4004: TOKEN_INVALID
|
||||||
|
* * 4010: SHARDING_INVALID
|
||||||
|
* * 4011: SHARDING_REQUIRED
|
||||||
|
* * 4013: INVALID_INTENTS
|
||||||
|
* * 4014: DISALLOWED_INTENTS
|
||||||
|
* @typedef {Object<number, string>} WSCodes
|
||||||
|
*/
|
||||||
exports.WSCodes = {
|
exports.WSCodes = {
|
||||||
1000: 'WS_CLOSE_REQUESTED',
|
1000: 'WS_CLOSE_REQUESTED',
|
||||||
|
1011: 'INTERNAL_ERROR',
|
||||||
4004: 'TOKEN_INVALID',
|
4004: 'TOKEN_INVALID',
|
||||||
4010: 'SHARDING_INVALID',
|
4010: 'SHARDING_INVALID',
|
||||||
4011: 'SHARDING_REQUIRED',
|
4011: 'SHARDING_REQUIRED',
|
||||||
@@ -40,7 +52,11 @@ function makeImageUrl(root, { format = 'webp', size } = {}) {
|
|||||||
* `4096`
|
* `4096`
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// https://discord.com/developers/docs/reference#image-formatting-cdn-endpoints
|
/**
|
||||||
|
* An object containing functions that return certain endpoints on the API.
|
||||||
|
* @typedef {Object<string, Function|string>} Endpoints
|
||||||
|
* @see {@link https://discord.com/developers/docs/reference#image-formatting-cdn-endpoints}
|
||||||
|
*/
|
||||||
exports.Endpoints = {
|
exports.Endpoints = {
|
||||||
CDN(root) {
|
CDN(root) {
|
||||||
return {
|
return {
|
||||||
@@ -77,6 +93,8 @@ exports.Endpoints = {
|
|||||||
`${root}/stickers/${stickerId}.${stickerFormat === 'LOTTIE' ? 'json' : 'png'}`,
|
`${root}/stickers/${stickerId}.${stickerFormat === 'LOTTIE' ? 'json' : 'png'}`,
|
||||||
RoleIcon: (roleId, hash, format = 'webp', size) =>
|
RoleIcon: (roleId, hash, format = 'webp', size) =>
|
||||||
makeImageUrl(`${root}/role-icons/${roleId}/${hash}`, { size, format }),
|
makeImageUrl(`${root}/role-icons/${roleId}/${hash}`, { size, format }),
|
||||||
|
guildScheduledEventCover: (scheduledEventId, coverHash, format, size) =>
|
||||||
|
makeImageUrl(`${root}/guild-events/${scheduledEventId}/${coverHash}`, { size, format }),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
invite: (root, code, eventId) => (eventId ? `${root}/${code}?event=${eventId}` : `${root}/${code}`),
|
invite: (root, code, eventId) => (eventId ? `${root}/${code}?event=${eventId}` : `${root}/${code}`),
|
||||||
@@ -95,7 +113,7 @@ exports.Endpoints = {
|
|||||||
* * WAITING_FOR_GUILDS: 6
|
* * WAITING_FOR_GUILDS: 6
|
||||||
* * IDENTIFYING: 7
|
* * IDENTIFYING: 7
|
||||||
* * RESUMING: 8
|
* * RESUMING: 8
|
||||||
* @typedef {number} Status
|
* @typedef {Object<string, number>} Status
|
||||||
*/
|
*/
|
||||||
exports.Status = {
|
exports.Status = {
|
||||||
READY: 0,
|
READY: 0,
|
||||||
@@ -109,6 +127,22 @@ exports.Status = {
|
|||||||
RESUMING: 8,
|
RESUMING: 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Opcodes sent to the Gateway:
|
||||||
|
* * DISPATCH: 0
|
||||||
|
* * HEARTBEAT: 1
|
||||||
|
* * IDENTIFY: 2
|
||||||
|
* * STATUS_UPDATE: 3
|
||||||
|
* * VOICE_STATE_UPDATE: 4
|
||||||
|
* * VOICE_GUILD_PING: 5
|
||||||
|
* * RESUME: 6
|
||||||
|
* * RECONNECT: 7
|
||||||
|
* * REQUEST_GUILD_MEMBERS: 8
|
||||||
|
* * INVALID_SESSION: 9
|
||||||
|
* * HELLO: 10
|
||||||
|
* * HEARTBEAT_ACK: 11
|
||||||
|
* @typedef {Object<string, number>} Opcodes
|
||||||
|
*/
|
||||||
exports.Opcodes = {
|
exports.Opcodes = {
|
||||||
DISPATCH: 0,
|
DISPATCH: 0,
|
||||||
HEARTBEAT: 1,
|
HEARTBEAT: 1,
|
||||||
@@ -124,23 +158,93 @@ exports.Opcodes = {
|
|||||||
HEARTBEAT_ACK: 11,
|
HEARTBEAT_ACK: 11,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The types of events emitted by the Client:
|
||||||
|
* * RATE_LIMIT: rateLimit
|
||||||
|
* * INVALID_REQUEST_WARNING: invalidRequestWarning
|
||||||
|
* * API_RESPONSE: apiResponse
|
||||||
|
* * API_REQUEST: apiRequest
|
||||||
|
* * CLIENT_READY: ready
|
||||||
|
* * APPLICATION_COMMAND_CREATE: applicationCommandCreate (deprecated)
|
||||||
|
* * APPLICATION_COMMAND_DELETE: applicationCommandDelete (deprecated)
|
||||||
|
* * APPLICATION_COMMAND_UPDATE: applicationCommandUpdate (deprecated)
|
||||||
|
* * GUILD_CREATE: guildCreate
|
||||||
|
* * GUILD_DELETE: guildDelete
|
||||||
|
* * GUILD_UPDATE: guildUpdate
|
||||||
|
* * GUILD_UNAVAILABLE: guildUnavailable
|
||||||
|
* * GUILD_MEMBER_ADD: guildMemberAdd
|
||||||
|
* * GUILD_MEMBER_REMOVE: guildMemberRemove
|
||||||
|
* * GUILD_MEMBER_UPDATE: guildMemberUpdate
|
||||||
|
* * GUILD_MEMBER_AVAILABLE: guildMemberAvailable
|
||||||
|
* * GUILD_MEMBERS_CHUNK: guildMembersChunk
|
||||||
|
* * GUILD_INTEGRATIONS_UPDATE: guildIntegrationsUpdate
|
||||||
|
* * GUILD_ROLE_CREATE: roleCreate
|
||||||
|
* * GUILD_ROLE_DELETE: roleDelete
|
||||||
|
* * INVITE_CREATE: inviteCreate
|
||||||
|
* * INVITE_DELETE: inviteDelete
|
||||||
|
* * GUILD_ROLE_UPDATE: roleUpdate
|
||||||
|
* * GUILD_EMOJI_CREATE: emojiCreate
|
||||||
|
* * GUILD_EMOJI_DELETE: emojiDelete
|
||||||
|
* * GUILD_EMOJI_UPDATE: emojiUpdate
|
||||||
|
* * GUILD_BAN_ADD: guildBanAdd
|
||||||
|
* * GUILD_BAN_REMOVE: guildBanRemove
|
||||||
|
* * CHANNEL_CREATE: channelCreate
|
||||||
|
* * CHANNEL_DELETE: channelDelete
|
||||||
|
* * CHANNEL_UPDATE: channelUpdate
|
||||||
|
* * CHANNEL_PINS_UPDATE: channelPinsUpdate
|
||||||
|
* * MESSAGE_CREATE: messageCreate
|
||||||
|
* * MESSAGE_DELETE: messageDelete
|
||||||
|
* * MESSAGE_UPDATE: messageUpdate
|
||||||
|
* * MESSAGE_BULK_DELETE: messageDeleteBulk
|
||||||
|
* * MESSAGE_REACTION_ADD: messageReactionAdd
|
||||||
|
* * MESSAGE_REACTION_REMOVE: messageReactionRemove
|
||||||
|
* * MESSAGE_REACTION_REMOVE_ALL: messageReactionRemoveAll
|
||||||
|
* * MESSAGE_REACTION_REMOVE_EMOJI: messageReactionRemoveEmoji
|
||||||
|
* * THREAD_CREATE: threadCreate
|
||||||
|
* * THREAD_DELETE: threadDelete
|
||||||
|
* * THREAD_UPDATE: threadUpdate
|
||||||
|
* * THREAD_LIST_SYNC: threadListSync
|
||||||
|
* * THREAD_MEMBER_UPDATE: threadMemberUpdate
|
||||||
|
* * THREAD_MEMBERS_UPDATE: threadMembersUpdate
|
||||||
|
* * USER_UPDATE: userUpdate
|
||||||
|
* * PRESENCE_UPDATE: presenceUpdate
|
||||||
|
* * VOICE_SERVER_UPDATE: voiceServerUpdate
|
||||||
|
* * VOICE_STATE_UPDATE: voiceStateUpdate
|
||||||
|
* * TYPING_START: typingStart
|
||||||
|
* * WEBHOOKS_UPDATE: webhookUpdate
|
||||||
|
* * INTERACTION_CREATE: interactionCreate
|
||||||
|
* * ERROR: error
|
||||||
|
* * WARN: warn
|
||||||
|
* * DEBUG: debug
|
||||||
|
* * CACHE_SWEEP: cacheSweep
|
||||||
|
* * SHARD_DISCONNECT: shardDisconnect
|
||||||
|
* * SHARD_ERROR: shardError
|
||||||
|
* * SHARD_RECONNECTING: shardReconnecting
|
||||||
|
* * SHARD_READY: shardReady
|
||||||
|
* * SHARD_RESUME: shardResume
|
||||||
|
* * INVALIDATED: invalidated
|
||||||
|
* * RAW: raw
|
||||||
|
* * STAGE_INSTANCE_CREATE: stageInstanceCreate
|
||||||
|
* * STAGE_INSTANCE_UPDATE: stageInstanceUpdate
|
||||||
|
* * STAGE_INSTANCE_DELETE: stageInstanceDelete
|
||||||
|
* * GUILD_STICKER_CREATE: stickerCreate
|
||||||
|
* * GUILD_STICKER_DELETE: stickerDelete
|
||||||
|
* * GUILD_STICKER_UPDATE: stickerUpdate
|
||||||
|
* * GUILD_SCHEDULED_EVENT_CREATE: guildScheduledEventCreate
|
||||||
|
* * GUILD_SCHEDULED_EVENT_UPDATE: guildScheduledEventUpdate
|
||||||
|
* * GUILD_SCHEDULED_EVENT_DELETE: guildScheduledEventDelete
|
||||||
|
* * GUILD_SCHEDULED_EVENT_USER_ADD: guildScheduledEventUserAdd
|
||||||
|
* * GUILD_SCHEDULED_EVENT_USER_REMOVE: guildScheduledEventUserRemove
|
||||||
|
* @typedef {Object<string, string>} Events
|
||||||
|
*/
|
||||||
exports.Events = {
|
exports.Events = {
|
||||||
RATE_LIMIT: 'rateLimit',
|
RATE_LIMIT: 'rateLimit',
|
||||||
INVALID_REQUEST_WARNING: 'invalidRequestWarning',
|
INVALID_REQUEST_WARNING: 'invalidRequestWarning',
|
||||||
API_RESPONSE: 'apiResponse',
|
API_RESPONSE: 'apiResponse',
|
||||||
API_REQUEST: 'apiRequest',
|
API_REQUEST: 'apiRequest',
|
||||||
CLIENT_READY: 'ready',
|
CLIENT_READY: 'ready',
|
||||||
/**
|
|
||||||
* @deprecated See {@link https://github.com/discord/discord-api-docs/issues/3690 this issue} for more information.
|
|
||||||
*/
|
|
||||||
APPLICATION_COMMAND_CREATE: 'applicationCommandCreate',
|
APPLICATION_COMMAND_CREATE: 'applicationCommandCreate',
|
||||||
/**
|
|
||||||
* @deprecated See {@link https://github.com/discord/discord-api-docs/issues/3690 this issue} for more information.
|
|
||||||
*/
|
|
||||||
APPLICATION_COMMAND_DELETE: 'applicationCommandDelete',
|
APPLICATION_COMMAND_DELETE: 'applicationCommandDelete',
|
||||||
/**
|
|
||||||
* @deprecated See {@link https://github.com/discord/discord-api-docs/issues/3690 this issue} for more information.
|
|
||||||
*/
|
|
||||||
APPLICATION_COMMAND_UPDATE: 'applicationCommandUpdate',
|
APPLICATION_COMMAND_UPDATE: 'applicationCommandUpdate',
|
||||||
GUILD_CREATE: 'guildCreate',
|
GUILD_CREATE: 'guildCreate',
|
||||||
GUILD_DELETE: 'guildDelete',
|
GUILD_DELETE: 'guildDelete',
|
||||||
@@ -211,6 +315,16 @@ exports.Events = {
|
|||||||
GUILD_SCHEDULED_EVENT_USER_REMOVE: 'guildScheduledEventUserRemove',
|
GUILD_SCHEDULED_EVENT_USER_REMOVE: 'guildScheduledEventUserRemove',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The types of events emitted by a Shard:
|
||||||
|
* * CLOSE: close
|
||||||
|
* * DESTROYED: destroyed
|
||||||
|
* * INVALID_SESSION: invalidSession
|
||||||
|
* * READY: ready
|
||||||
|
* * RESUMED: resumed
|
||||||
|
* * ALL_READY: allReady
|
||||||
|
* @typedef {Object<string, string>} ShardEvents
|
||||||
|
*/
|
||||||
exports.ShardEvents = {
|
exports.ShardEvents = {
|
||||||
CLOSE: 'close',
|
CLOSE: 'close',
|
||||||
DESTROYED: 'destroyed',
|
DESTROYED: 'destroyed',
|
||||||
@@ -527,6 +641,7 @@ exports.ActivityTypes = createEnum(['PLAYING', 'STREAMING', 'LISTENING', 'WATCHI
|
|||||||
* * `GUILD_PUBLIC_THREAD` - a guild text channel's public thread channel
|
* * `GUILD_PUBLIC_THREAD` - a guild text channel's public thread channel
|
||||||
* * `GUILD_PRIVATE_THREAD` - a guild text channel's private thread channel
|
* * `GUILD_PRIVATE_THREAD` - a guild text channel's private thread channel
|
||||||
* * `GUILD_STAGE_VOICE` - a guild stage voice channel
|
* * `GUILD_STAGE_VOICE` - a guild stage voice channel
|
||||||
|
* * `GUILD_DIRECTORY` - the channel in a hub containing guilds
|
||||||
* * `UNKNOWN` - a generic channel of unknown type, could be Channel or GuildChannel
|
* * `UNKNOWN` - a generic channel of unknown type, could be Channel or GuildChannel
|
||||||
* @typedef {string} ChannelType
|
* @typedef {string} ChannelType
|
||||||
* @see {@link https://discord.com/developers/docs/resources/channel#channel-object-channel-types}
|
* @see {@link https://discord.com/developers/docs/resources/channel#channel-object-channel-types}
|
||||||
@@ -545,6 +660,7 @@ exports.ChannelTypes = createEnum([
|
|||||||
'GUILD_PUBLIC_THREAD',
|
'GUILD_PUBLIC_THREAD',
|
||||||
'GUILD_PRIVATE_THREAD',
|
'GUILD_PRIVATE_THREAD',
|
||||||
'GUILD_STAGE_VOICE',
|
'GUILD_STAGE_VOICE',
|
||||||
|
'GUILD_DIRECTORY',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -553,7 +669,15 @@ exports.ChannelTypes = createEnum([
|
|||||||
* * TextChannel
|
* * TextChannel
|
||||||
* * NewsChannel
|
* * NewsChannel
|
||||||
* * ThreadChannel
|
* * ThreadChannel
|
||||||
* @typedef {DMChannel|TextChannel|NewsChannel|ThreadChannel} TextBasedChannels
|
* * VoiceChannel
|
||||||
|
* @typedef {DMChannel|TextChannel|NewsChannel|ThreadChannel|VoiceChannel} TextBasedChannels
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data that resolves to give a text-based channel. This can be:
|
||||||
|
* * A text-based channel
|
||||||
|
* * A snowflake
|
||||||
|
* @typedef {TextBasedChannels|Snowflake} TextBasedChannelsResolvable
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -564,6 +688,7 @@ exports.ChannelTypes = createEnum([
|
|||||||
* * GUILD_NEWS_THREAD
|
* * GUILD_NEWS_THREAD
|
||||||
* * GUILD_PUBLIC_THREAD
|
* * GUILD_PUBLIC_THREAD
|
||||||
* * GUILD_PRIVATE_THREAD
|
* * GUILD_PRIVATE_THREAD
|
||||||
|
* * GUILD_VOICE
|
||||||
* @typedef {string} TextBasedChannelTypes
|
* @typedef {string} TextBasedChannelTypes
|
||||||
*/
|
*/
|
||||||
exports.TextBasedChannelTypes = [
|
exports.TextBasedChannelTypes = [
|
||||||
@@ -573,6 +698,7 @@ exports.TextBasedChannelTypes = [
|
|||||||
'GUILD_NEWS_THREAD',
|
'GUILD_NEWS_THREAD',
|
||||||
'GUILD_PUBLIC_THREAD',
|
'GUILD_PUBLIC_THREAD',
|
||||||
'GUILD_PRIVATE_THREAD',
|
'GUILD_PRIVATE_THREAD',
|
||||||
|
'GUILD_VOICE',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -592,11 +718,51 @@ exports.ThreadChannelTypes = ['GUILD_NEWS_THREAD', 'GUILD_PUBLIC_THREAD', 'GUILD
|
|||||||
*/
|
*/
|
||||||
exports.VoiceBasedChannelTypes = ['GUILD_VOICE', 'GUILD_STAGE_VOICE'];
|
exports.VoiceBasedChannelTypes = ['GUILD_VOICE', 'GUILD_STAGE_VOICE'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The types of assets of an application:
|
||||||
|
* * SMALL: 1
|
||||||
|
* * BIG: 2
|
||||||
|
* @typedef {Object<string, number>} ClientApplicationAssetTypes
|
||||||
|
*/
|
||||||
exports.ClientApplicationAssetTypes = {
|
exports.ClientApplicationAssetTypes = {
|
||||||
SMALL: 1,
|
SMALL: 1,
|
||||||
BIG: 2,
|
BIG: 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A commonly used color:
|
||||||
|
* * DEFAULT
|
||||||
|
* * WHITE
|
||||||
|
* * AQUA
|
||||||
|
* * GREEN
|
||||||
|
* * BLUE
|
||||||
|
* * YELLOW
|
||||||
|
* * PURPLE
|
||||||
|
* * LUMINOUS_VIVID_PINK
|
||||||
|
* * FUCHSIA
|
||||||
|
* * GOLD
|
||||||
|
* * ORANGE
|
||||||
|
* * RED
|
||||||
|
* * GREY
|
||||||
|
* * NAVY
|
||||||
|
* * DARK_AQUA
|
||||||
|
* * DARK_GREEN
|
||||||
|
* * DARK_BLUE
|
||||||
|
* * DARK_PURPLE
|
||||||
|
* * DARK_VIVID_PINK
|
||||||
|
* * DARK_GOLD
|
||||||
|
* * DARK_ORANGE
|
||||||
|
* * DARK_RED
|
||||||
|
* * DARK_GREY
|
||||||
|
* * DARKER_GREY
|
||||||
|
* * LIGHT_GREY
|
||||||
|
* * DARK_NAVY
|
||||||
|
* * BLURPLE
|
||||||
|
* * GREYPLE
|
||||||
|
* * DARK_BUT_NOT_BLACK
|
||||||
|
* * NOT_QUITE_BLACK
|
||||||
|
* @typedef {string} Color
|
||||||
|
*/
|
||||||
exports.Colors = {
|
exports.Colors = {
|
||||||
DEFAULT: 0x000000,
|
DEFAULT: 0x000000,
|
||||||
WHITE: 0xffffff,
|
WHITE: 0xffffff,
|
||||||
@@ -768,6 +934,7 @@ exports.VerificationLevels = createEnum(['NONE', 'LOW', 'MEDIUM', 'HIGH', 'VERY_
|
|||||||
* * INVALID_FILE_UPLOADED
|
* * INVALID_FILE_UPLOADED
|
||||||
* * CANNOT_SELF_REDEEM_GIFT
|
* * CANNOT_SELF_REDEEM_GIFT
|
||||||
* * INVALID_GUILD
|
* * INVALID_GUILD
|
||||||
|
* * INVALID_MESSAGE_TYPE
|
||||||
* * PAYMENT_SOURCE_REQUIRED
|
* * PAYMENT_SOURCE_REQUIRED
|
||||||
* * CANNOT_DELETE_COMMUNITY_REQUIRED_CHANNEL
|
* * CANNOT_DELETE_COMMUNITY_REQUIRED_CHANNEL
|
||||||
* * INVALID_STICKER_SENT
|
* * INVALID_STICKER_SENT
|
||||||
@@ -787,7 +954,7 @@ exports.VerificationLevels = createEnum(['NONE', 'LOW', 'MEDIUM', 'HIGH', 'VERY_
|
|||||||
* * MESSAGE_ALREADY_HAS_THREAD
|
* * MESSAGE_ALREADY_HAS_THREAD
|
||||||
* * THREAD_LOCKED
|
* * THREAD_LOCKED
|
||||||
* * MAXIMUM_ACTIVE_THREADS
|
* * MAXIMUM_ACTIVE_THREADS
|
||||||
* * MAXIMUM_ACTIVE_ANNOUNCEMENT_THREAD
|
* * MAXIMUM_ACTIVE_ANNOUNCEMENT_THREADS
|
||||||
* * INVALID_JSON_FOR_UPLOADED_LOTTIE_FILE
|
* * INVALID_JSON_FOR_UPLOADED_LOTTIE_FILE
|
||||||
* * UPLOADED_LOTTIES_CANNOT_CONTAIN_RASTERIZED_IMAGES
|
* * UPLOADED_LOTTIES_CANNOT_CONTAIN_RASTERIZED_IMAGES
|
||||||
* * STICKER_MAXIMUM_FRAMERATE_EXCEEDED
|
* * STICKER_MAXIMUM_FRAMERATE_EXCEEDED
|
||||||
@@ -915,6 +1082,7 @@ exports.APIErrors = {
|
|||||||
INVALID_FILE_UPLOADED: 50046,
|
INVALID_FILE_UPLOADED: 50046,
|
||||||
CANNOT_SELF_REDEEM_GIFT: 50054,
|
CANNOT_SELF_REDEEM_GIFT: 50054,
|
||||||
INVALID_GUILD: 50055,
|
INVALID_GUILD: 50055,
|
||||||
|
INVALID_MESSAGE_TYPE: 50068,
|
||||||
PAYMENT_SOURCE_REQUIRED: 50070,
|
PAYMENT_SOURCE_REQUIRED: 50070,
|
||||||
CANNOT_DELETE_COMMUNITY_REQUIRED_CHANNEL: 50074,
|
CANNOT_DELETE_COMMUNITY_REQUIRED_CHANNEL: 50074,
|
||||||
INVALID_STICKER_SENT: 50081,
|
INVALID_STICKER_SENT: 50081,
|
||||||
@@ -1025,6 +1193,7 @@ exports.ApplicationCommandTypes = createEnum([null, 'CHAT_INPUT', 'USER', 'MESSA
|
|||||||
* * ROLE
|
* * ROLE
|
||||||
* * MENTIONABLE
|
* * MENTIONABLE
|
||||||
* * NUMBER
|
* * NUMBER
|
||||||
|
* * ATTACHMENT
|
||||||
* @typedef {string} ApplicationCommandOptionType
|
* @typedef {string} ApplicationCommandOptionType
|
||||||
* @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-type}
|
* @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-type}
|
||||||
*/
|
*/
|
||||||
@@ -1040,6 +1209,7 @@ exports.ApplicationCommandOptionTypes = createEnum([
|
|||||||
'ROLE',
|
'ROLE',
|
||||||
'MENTIONABLE',
|
'MENTIONABLE',
|
||||||
'NUMBER',
|
'NUMBER',
|
||||||
|
'ATTACHMENT',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1057,6 +1227,7 @@ exports.ApplicationCommandPermissionTypes = createEnum([null, 'ROLE', 'USER']);
|
|||||||
* * APPLICATION_COMMAND
|
* * APPLICATION_COMMAND
|
||||||
* * MESSAGE_COMPONENT
|
* * MESSAGE_COMPONENT
|
||||||
* * APPLICATION_COMMAND_AUTOCOMPLETE
|
* * APPLICATION_COMMAND_AUTOCOMPLETE
|
||||||
|
* * MODAL_SUBMIT
|
||||||
* @typedef {string} InteractionType
|
* @typedef {string} InteractionType
|
||||||
* @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-type}
|
* @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-type}
|
||||||
*/
|
*/
|
||||||
@@ -1066,6 +1237,7 @@ exports.InteractionTypes = createEnum([
|
|||||||
'APPLICATION_COMMAND',
|
'APPLICATION_COMMAND',
|
||||||
'MESSAGE_COMPONENT',
|
'MESSAGE_COMPONENT',
|
||||||
'APPLICATION_COMMAND_AUTOCOMPLETE',
|
'APPLICATION_COMMAND_AUTOCOMPLETE',
|
||||||
|
'MODAL_SUBMIT',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1076,6 +1248,7 @@ exports.InteractionTypes = createEnum([
|
|||||||
* * DEFERRED_MESSAGE_UPDATE
|
* * DEFERRED_MESSAGE_UPDATE
|
||||||
* * UPDATE_MESSAGE
|
* * UPDATE_MESSAGE
|
||||||
* * APPLICATION_COMMAND_AUTOCOMPLETE_RESULT
|
* * APPLICATION_COMMAND_AUTOCOMPLETE_RESULT
|
||||||
|
* * MODAL
|
||||||
* @typedef {string} InteractionResponseType
|
* @typedef {string} InteractionResponseType
|
||||||
* @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-interaction-callback-type}
|
* @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-interaction-callback-type}
|
||||||
*/
|
*/
|
||||||
@@ -1089,6 +1262,7 @@ exports.InteractionResponseTypes = createEnum([
|
|||||||
'DEFERRED_MESSAGE_UPDATE',
|
'DEFERRED_MESSAGE_UPDATE',
|
||||||
'UPDATE_MESSAGE',
|
'UPDATE_MESSAGE',
|
||||||
'APPLICATION_COMMAND_AUTOCOMPLETE_RESULT',
|
'APPLICATION_COMMAND_AUTOCOMPLETE_RESULT',
|
||||||
|
'MODAL',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1096,10 +1270,11 @@ exports.InteractionResponseTypes = createEnum([
|
|||||||
* * ACTION_ROW
|
* * ACTION_ROW
|
||||||
* * BUTTON
|
* * BUTTON
|
||||||
* * SELECT_MENU
|
* * SELECT_MENU
|
||||||
|
* * TEXT_INPUT
|
||||||
* @typedef {string} MessageComponentType
|
* @typedef {string} MessageComponentType
|
||||||
* @see {@link https://discord.com/developers/docs/interactions/message-components#component-object-component-types}
|
* @see {@link https://discord.com/developers/docs/interactions/message-components#component-object-component-types}
|
||||||
*/
|
*/
|
||||||
exports.MessageComponentTypes = createEnum([null, 'ACTION_ROW', 'BUTTON', 'SELECT_MENU']);
|
exports.MessageComponentTypes = createEnum([null, 'ACTION_ROW', 'BUTTON', 'SELECT_MENU', 'TEXT_INPUT']);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The style of a message button
|
* The style of a message button
|
||||||
@@ -1142,6 +1317,15 @@ exports.NSFWLevels = createEnum(['DEFAULT', 'EXPLICIT', 'SAFE', 'AGE_RESTRICTED'
|
|||||||
*/
|
*/
|
||||||
exports.PrivacyLevels = createEnum([null, 'PUBLIC', 'GUILD_ONLY']);
|
exports.PrivacyLevels = createEnum([null, 'PUBLIC', 'GUILD_ONLY']);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The style of a text input component
|
||||||
|
* * SHORT
|
||||||
|
* * PARAGRAPH
|
||||||
|
* @typedef {string} TextInputStyle
|
||||||
|
* @see {@link https://discord.com/developers/docs/interactions/message-components#text-inputs-text-input-styles}
|
||||||
|
*/
|
||||||
|
exports.TextInputStyles = createEnum([null, 'SHORT', 'PARAGRAPH']);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Privacy level of a {@link GuildScheduledEvent} object:
|
* Privacy level of a {@link GuildScheduledEvent} object:
|
||||||
* * GUILD_ONLY
|
* * GUILD_ONLY
|
||||||
@@ -1184,6 +1368,15 @@ exports.GuildScheduledEventStatuses = createEnum([null, 'SCHEDULED', 'ACTIVE', '
|
|||||||
exports.GuildScheduledEventEntityTypes = createEnum([null, 'STAGE_INSTANCE', 'VOICE', 'EXTERNAL']);
|
exports.GuildScheduledEventEntityTypes = createEnum([null, 'STAGE_INSTANCE', 'VOICE', 'EXTERNAL']);
|
||||||
/* eslint-enable max-len */
|
/* eslint-enable max-len */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The camera video quality mode of a {@link VoiceChannel}:
|
||||||
|
* * AUTO
|
||||||
|
* * FULL
|
||||||
|
* @typedef {string} VideoQualityMode
|
||||||
|
* @see {@link https://discord.com/developers/docs/resources/channel#channel-object-video-quality-modes}
|
||||||
|
*/
|
||||||
|
exports.VideoQualityModes = createEnum([null, 'AUTO', 'FULL']);
|
||||||
|
|
||||||
exports._cleanupSymbol = Symbol('djsCleanup');
|
exports._cleanupSymbol = Symbol('djsCleanup');
|
||||||
|
|
||||||
function keyMirror(arr) {
|
function keyMirror(arr) {
|
||||||
@@ -1204,37 +1397,58 @@ function createEnum(keys) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} Constants Constants that can be used in an enum or object-like way.
|
* @typedef {Object} Constants Constants that can be used in an enum or object-like way.
|
||||||
* @property {ActivityType} ActivityTypes The type of an activity of a users presence.
|
* @property {Object<ActivityType, number>} ActivityTypes The type of an activity of a users presence.
|
||||||
* @property {APIError} APIErrors An error encountered while performing an API request.
|
* @property {Object<APIError, number>} APIErrors An error encountered while performing an API request.
|
||||||
* @property {ApplicationCommandOptionType} ApplicationCommandOptionTypes
|
* @property {Object<ApplicationCommandOptionType, number>} ApplicationCommandOptionTypes
|
||||||
* The type of an {@link ApplicationCommandOption} object.
|
* The type of an {@link ApplicationCommandOption} object.
|
||||||
* @property {ApplicationCommandPermissionType} ApplicationCommandPermissionTypes
|
* @property {Object<ApplicationCommandPermissionType, number>} ApplicationCommandPermissionTypes
|
||||||
* The type of an {@link ApplicationCommandPermissions} object.
|
* The type of an {@link ApplicationCommandPermissions} object.
|
||||||
* @property {ChannelType} ChannelTypes All available channel types.
|
* @property {Object<ApplicationCommandType, number>} ApplicationCommandTypes
|
||||||
* @property {DefaultMessageNotificationLevel} DefaultMessageNotificationLevels
|
* The type of an {@link ApplicationCommand} object.
|
||||||
* The value set for a guild's default message notifications.
|
* @property {Object<ChannelType, number>} ChannelTypes All available channel types.
|
||||||
* @property {ExplicitContentFilterLevel} ExplicitContentFilterLevels
|
* @property {ClientApplicationAssetTypes} ClientApplicationAssetTypes The types of an {@link ApplicationAsset} object.
|
||||||
|
* @property {Object<Color, number>} Colors An object with regularly used colors.
|
||||||
|
* @property {Object<DefaultMessageNotificationLevel, number>} DefaultMessageNotificationLevels
|
||||||
|
* The value set for a guilds default message notifications.
|
||||||
|
* @property {Endpoints} Endpoints Object containing functions that return certain endpoints on the API.
|
||||||
|
* @property {Events} Events The types of events emitted by the Client.
|
||||||
|
* @property {Object<ExplicitContentFilterLevel, number>} ExplicitContentFilterLevels
|
||||||
* The value set for the explicit content filter levels for a guild.
|
* The value set for the explicit content filter levels for a guild.
|
||||||
* @property {GuildScheduledEventStatus} GuildScheduledEventStatuses The status of a {@link GuildScheduledEvent} object.
|
* @property {Object<GuildScheduledEventEntityType, number>} GuildScheduledEventEntityTypes
|
||||||
* @property {GuildScheduledEventEntityType} GuildScheduledEventEntityTypes The entity type of a
|
* The entity type of a {@link GuildScheduledEvent} object.
|
||||||
* {@link GuildScheduledEvent} object.
|
* @property {Object<GuildScheduledEventPrivacyLevel, number>} GuildScheduledEventPrivacyLevels
|
||||||
* @property {GuildScheduledEventPrivacyLevel} GuildScheduledEventPrivacyLevels Privacy level of a
|
* Privacy level of a {@link GuildScheduledEvent} object.
|
||||||
* {@link GuildScheduledEvent} object.
|
* @property {Object<GuildScheduledEventStatus, number>} GuildScheduledEventStatuses
|
||||||
* @property {InteractionResponseType} InteractionResponseTypes The type of an interaction response.
|
* The status of a {@link GuildScheduledEvent} object.
|
||||||
* @property {InteractionType} InteractionTypes The type of an {@link Interaction} object.
|
* @property {Object<IntegrationExpireBehavior, number>} IntegrationExpireBehaviors
|
||||||
* @property {MembershipState} MembershipStates The value set for a team member's membership state.
|
* The behavior of expiring subscribers for Integrations.
|
||||||
* @property {MessageButtonStyle} MessageButtonStyles The style of a message button.
|
* @property {Object<InteractionResponseType, number>} InteractionResponseTypes The type of an interaction response.
|
||||||
* @property {MessageComponentType} MessageComponentTypes The type of a message component.
|
* @property {Object<InteractionType, number>} InteractionTypes The type of an {@link Interaction} object.
|
||||||
* @property {MFALevel} MFALevels The required MFA level for a guild.
|
* @property {InviteScope[]} InviteScopes The scopes of an invite.
|
||||||
* @property {NSFWLevel} NSFWLevels NSFW level of a guild.
|
* @property {Object<MembershipState, number>} MembershipStates The value set for a team members membership state.
|
||||||
* @property {OverwriteType} OverwriteTypes An overwrite type.
|
* @property {Object<MessageButtonStyle, number>} MessageButtonStyles The style of a message button.
|
||||||
* @property {PartialType} PartialTypes The type of Structure allowed to be a partial.
|
* @property {Object<MessageComponentType, number>} MessageComponentTypes The type of a message component.
|
||||||
* @property {PremiumTier} PremiumTiers The premium tier (Server Boost level) of a guild.
|
* @property {Object<MFALevel, number>} MFALevels The required MFA level for a guild.
|
||||||
* @property {PrivacyLevel} PrivacyLevels Privacy level of a {@link StageInstance} object.
|
* @property {Object<NSFWLevel, number>} NSFWLevels NSFW level of a guild.
|
||||||
|
* @property {Opcodes} Opcodes The types of Opcodes sent to the Gateway.
|
||||||
|
* @property {Object<OverwriteType, number>} OverwriteTypes An overwrite type.
|
||||||
|
* @property {Object} Package The package.json of the library.
|
||||||
|
* @property {Object<PartialType, PartialType>} PartialTypes The type of Structure allowed to be a partial.
|
||||||
|
* @property {Object<PremiumTier, number>} PremiumTiers The premium tier (Server Boost level) of a guild.
|
||||||
|
* @property {Object<PrivacyLevel, number>} PrivacyLevels Privacy level of a {@link StageInstance} object.
|
||||||
|
* @property {ShardEvents} ShardEvents The type of events emitted by a Shard.
|
||||||
* @property {Status} Status The available statuses of the client.
|
* @property {Status} Status The available statuses of the client.
|
||||||
* @property {StickerFormatType} StickerFormatTypes The value set for a sticker's format type.
|
* @property {Object<StickerFormatType, number>} StickerFormatTypes The value set for a stickers format type.
|
||||||
* @property {StickerType} StickerTypes The value set for a sticker's type.
|
* @property {Object<StickerType, number>} StickerTypes The value set for a stickers type.
|
||||||
* @property {VerificationLevel} VerificationLevels The value set for the verification levels for a guild.
|
* @property {SweeperKey[]} SweeperKeys The name of an item to be swept in Sweepers.
|
||||||
* @property {WebhookType} WebhookTypes The value set for a webhook's type.
|
* @property {SystemMessageType[]} SystemMessageTypes The types of messages that are `System`.
|
||||||
* @property {WSEventType} WSEvents The type of a WebSocket message event.
|
* @property {Object<TextInputStyle, number>} TextInputStyles The style of a text input component.
|
||||||
|
* @property {string} UserAgent The user agent used for requests.
|
||||||
|
* @property {Object<VerificationLevel, number>} VerificationLevels
|
||||||
|
* The value set for the verification levels for a guild.
|
||||||
|
* @property {Object<VideoQualityMode, number>} VideoQualityModes
|
||||||
|
* The camera video quality mode for a {@link VoiceChannel}.
|
||||||
|
* @property {Object<WebhookType, number>} WebhookTypes The value set for a webhooks type.
|
||||||
|
* @property {WSCodes} WSCodes The types of WebSocket error codes.
|
||||||
|
* @property {Object<WSEventType, WSEventType>} WSEvents The type of a WebSocket message event.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class DataResolver extends null {
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
static resolveCode(data, regex) {
|
static resolveCode(data, regex) {
|
||||||
return data.matchAll(regex).next().value?.[1] ?? data;
|
return new RegExp(regex.source).exec(data)?.[1] ?? data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ const {
|
|||||||
hyperlink,
|
hyperlink,
|
||||||
inlineCode,
|
inlineCode,
|
||||||
italic,
|
italic,
|
||||||
memberNicknameMention,
|
|
||||||
quote,
|
quote,
|
||||||
roleMention,
|
roleMention,
|
||||||
spoiler,
|
spoiler,
|
||||||
@@ -111,15 +110,6 @@ Formatters.inlineCode = inlineCode;
|
|||||||
*/
|
*/
|
||||||
Formatters.italic = italic;
|
Formatters.italic = italic;
|
||||||
|
|
||||||
/**
|
|
||||||
* Formats a user id into a member-nickname mention.
|
|
||||||
* @method memberNicknameMention
|
|
||||||
* @memberof Formatters
|
|
||||||
* @param {string} memberId The user id to format.
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
Formatters.memberNicknameMention = memberNicknameMention;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats the content into a quote. This needs to be at the start of the line for Discord to format it.
|
* Formats the content into a quote. This needs to be at the start of the line for Discord to format it.
|
||||||
* @method quote
|
* @method quote
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ const process = require('node:process');
|
|||||||
/**
|
/**
|
||||||
* Rate limit data
|
* Rate limit data
|
||||||
* @typedef {Object} RateLimitData
|
* @typedef {Object} RateLimitData
|
||||||
* @property {number} timeout Time until this rate limit ends, in ms
|
* @property {number} timeout Time until this rate limit ends, in milliseconds
|
||||||
* @property {number} limit The maximum amount of requests of this endpoint
|
* @property {number} limit The maximum amount of requests of this endpoint
|
||||||
* @property {string} method The HTTP method of this request
|
* @property {string} method The HTTP method of this request
|
||||||
* @property {string} path The path of the request relative to the HTTP endpoint
|
* @property {string} path The path of the request relative to the HTTP endpoint
|
||||||
@@ -33,6 +33,9 @@ const process = require('node:process');
|
|||||||
* @property {number|number[]|string} [shards] The shard's id to run, or an array of shard ids. If not specified,
|
* @property {number|number[]|string} [shards] The shard's id to run, or an array of shard ids. If not specified,
|
||||||
* the client will spawn {@link ClientOptions#shardCount} shards. If set to `auto`, it will fetch the
|
* the client will spawn {@link ClientOptions#shardCount} shards. If set to `auto`, it will fetch the
|
||||||
* recommended amount of shards from Discord and spawn that amount
|
* recommended amount of shards from Discord and spawn that amount
|
||||||
|
* @property {number} [closeTimeout=5000] The amount of time in milliseconds to wait for the close frame to be received
|
||||||
|
* from the WebSocket.
|
||||||
|
* <info>Don't have this too high/low. It's best to have it between 2000-6000 ms.</info>
|
||||||
* @property {number} [shardCount=1] The total amount of shards used by all processes of this bot
|
* @property {number} [shardCount=1] The total amount of shards used by all processes of this bot
|
||||||
* (e.g. recommended shard count, shard count of the ShardingManager)
|
* (e.g. recommended shard count, shard count of the ShardingManager)
|
||||||
* @property {CacheFactory} [makeCache] Function to create a cache.
|
* @property {CacheFactory} [makeCache] Function to create a cache.
|
||||||
@@ -73,7 +76,7 @@ const process = require('node:process');
|
|||||||
* @property {PresenceData} [presence={}] Presence data to use upon login
|
* @property {PresenceData} [presence={}] Presence data to use upon login
|
||||||
* @property {IntentsResolvable} intents Intents to enable for this connection
|
* @property {IntentsResolvable} intents Intents to enable for this connection
|
||||||
* @property {number} [waitGuildTimeout=15_000] Time in milliseconds that Clients with the GUILDS intent should wait for
|
* @property {number} [waitGuildTimeout=15_000] Time in milliseconds that Clients with the GUILDS intent should wait for
|
||||||
* missing guilds to be recieved before starting the bot. If not specified, the default is 15 seconds.
|
* missing guilds to be received before starting the bot. If not specified, the default is 15 seconds.
|
||||||
* @property {SweeperOptions} [sweepers={}] Options for cache sweeping
|
* @property {SweeperOptions} [sweepers={}] Options for cache sweeping
|
||||||
* @property {WebsocketOptions} [ws] Options for the WebSocket
|
* @property {WebsocketOptions} [ws] Options for the WebSocket
|
||||||
* @property {HTTPOptions} [http] HTTP options
|
* @property {HTTPOptions} [http] HTTP options
|
||||||
@@ -132,6 +135,7 @@ class Options extends null {
|
|||||||
*/
|
*/
|
||||||
static createDefault() {
|
static createDefault() {
|
||||||
return {
|
return {
|
||||||
|
closeTimeout: 5_000,
|
||||||
waitGuildTimeout: 15_000,
|
waitGuildTimeout: 15_000,
|
||||||
shardCount: 1,
|
shardCount: 1,
|
||||||
makeCache: this.cacheWithLimits(this.defaultMakeCacheSettings),
|
makeCache: this.cacheWithLimits(this.defaultMakeCacheSettings),
|
||||||
@@ -153,9 +157,9 @@ class Options extends null {
|
|||||||
large_threshold: 50,
|
large_threshold: 50,
|
||||||
compress: false,
|
compress: false,
|
||||||
properties: {
|
properties: {
|
||||||
$os: process.platform,
|
os: process.platform,
|
||||||
$browser: 'discord.js',
|
browser: 'discord.js',
|
||||||
$device: 'discord.js',
|
device: 'discord.js',
|
||||||
},
|
},
|
||||||
version: 9,
|
version: 9,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class SnowflakeUtil extends null {
|
|||||||
* ```
|
* ```
|
||||||
* 64 22 17 12 0
|
* 64 22 17 12 0
|
||||||
* 000000111011000111100001101001000101000000 00001 00000 000000000000
|
* 000000111011000111100001101001000101000000 00001 00000 000000000000
|
||||||
* number of ms since Discord epoch worker pid increment
|
* number of milliseconds since Discord epoch worker pid increment
|
||||||
* ```
|
* ```
|
||||||
* @typedef {string} Snowflake
|
* @typedef {string} Snowflake
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -192,6 +192,15 @@ class Sweepers {
|
|||||||
return this._sweepGuildDirectProp('stageInstances', filter, { outputName: 'stage instances' }).items;
|
return this._sweepGuildDirectProp('stageInstances', filter, { outputName: 'stage instances' }).items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sweeps all guild stickers and removes the ones which are indicated by the filter.
|
||||||
|
* @param {Function} filter The function used to determine which stickers will be removed from the caches.
|
||||||
|
* @returns {number} Amount of stickers that were removed from the caches
|
||||||
|
*/
|
||||||
|
sweepStickers(filter) {
|
||||||
|
return this._sweepGuildDirectProp('stickers', filter).items;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sweeps all thread members and removes the ones which are indicated by the filter.
|
* Sweeps all thread members and removes the ones which are indicated by the filter.
|
||||||
* <info>It is highly recommended to keep the client thread member cached</info>
|
* <info>It is highly recommended to keep the client thread member cached</info>
|
||||||
@@ -375,11 +384,11 @@ class Sweepers {
|
|||||||
* Sweep a direct sub property of all guilds
|
* Sweep a direct sub property of all guilds
|
||||||
* @param {string} key The name of the property
|
* @param {string} key The name of the property
|
||||||
* @param {Function} filter Filter function passed to sweep
|
* @param {Function} filter Filter function passed to sweep
|
||||||
* @param {SweepEventOptions} [eventOptions] Options for the Client event emitted here
|
* @param {SweepEventOptions} [eventOptions={}] Options for the Client event emitted here
|
||||||
* @returns {Object} Object containing the number of guilds swept and the number of items swept
|
* @returns {Object} Object containing the number of guilds swept and the number of items swept
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_sweepGuildDirectProp(key, filter, { emit = true, outputName }) {
|
_sweepGuildDirectProp(key, filter, { emit = true, outputName } = {}) {
|
||||||
if (typeof filter !== 'function') {
|
if (typeof filter !== 'function') {
|
||||||
throw new TypeError('INVALID_TYPE', 'filter', 'function');
|
throw new TypeError('INVALID_TYPE', 'filter', 'function');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ const { Error: DiscordError, RangeError, TypeError } = require('../errors');
|
|||||||
const has = (o, k) => Object.prototype.hasOwnProperty.call(o, k);
|
const has = (o, k) => Object.prototype.hasOwnProperty.call(o, k);
|
||||||
const isObject = d => typeof d === 'object' && d !== null;
|
const isObject = d => typeof d === 'object' && d !== null;
|
||||||
|
|
||||||
|
let deprecationEmittedForSplitMessage = false;
|
||||||
let deprecationEmittedForRemoveMentions = false;
|
let deprecationEmittedForRemoveMentions = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,9 +71,19 @@ class Util extends null {
|
|||||||
* Splits a string into multiple chunks at a designated character that do not exceed a specific length.
|
* Splits a string into multiple chunks at a designated character that do not exceed a specific length.
|
||||||
* @param {string} text Content to split
|
* @param {string} text Content to split
|
||||||
* @param {SplitOptions} [options] Options controlling the behavior of the split
|
* @param {SplitOptions} [options] Options controlling the behavior of the split
|
||||||
|
* @deprecated This will be removed in the next major version.
|
||||||
* @returns {string[]}
|
* @returns {string[]}
|
||||||
*/
|
*/
|
||||||
static splitMessage(text, { maxLength = 2_000, char = '\n', prepend = '', append = '' } = {}) {
|
static splitMessage(text, { maxLength = 2_000, char = '\n', prepend = '', append = '' } = {}) {
|
||||||
|
if (!deprecationEmittedForSplitMessage) {
|
||||||
|
process.emitWarning(
|
||||||
|
'The Util.splitMessage method is deprecated and will be removed in the next major version.',
|
||||||
|
'DeprecationWarning',
|
||||||
|
);
|
||||||
|
|
||||||
|
deprecationEmittedForSplitMessage = true;
|
||||||
|
}
|
||||||
|
|
||||||
text = Util.verifyString(text);
|
text = Util.verifyString(text);
|
||||||
if (text.length <= maxLength) return [text];
|
if (text.length <= maxLength) return [text];
|
||||||
let splitText = [text];
|
let splitText = [text];
|
||||||
@@ -419,43 +430,11 @@ class Util extends null {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Can be a number, hex string, an RGB array like:
|
* Can be a number, hex string, a {@link Color}, or an RGB array like:
|
||||||
* ```js
|
* ```js
|
||||||
* [255, 0, 255] // purple
|
* [255, 0, 255] // purple
|
||||||
* ```
|
* ```
|
||||||
* or one of the following strings:
|
* @typedef {string|Color|number|number[]} ColorResolvable
|
||||||
* - `DEFAULT`
|
|
||||||
* - `WHITE`
|
|
||||||
* - `AQUA`
|
|
||||||
* - `GREEN`
|
|
||||||
* - `BLUE`
|
|
||||||
* - `YELLOW`
|
|
||||||
* - `PURPLE`
|
|
||||||
* - `LUMINOUS_VIVID_PINK`
|
|
||||||
* - `FUCHSIA`
|
|
||||||
* - `GOLD`
|
|
||||||
* - `ORANGE`
|
|
||||||
* - `RED`
|
|
||||||
* - `GREY`
|
|
||||||
* - `NAVY`
|
|
||||||
* - `DARK_AQUA`
|
|
||||||
* - `DARK_GREEN`
|
|
||||||
* - `DARK_BLUE`
|
|
||||||
* - `DARK_PURPLE`
|
|
||||||
* - `DARK_VIVID_PINK`
|
|
||||||
* - `DARK_GOLD`
|
|
||||||
* - `DARK_ORANGE`
|
|
||||||
* - `DARK_RED`
|
|
||||||
* - `DARK_GREY`
|
|
||||||
* - `DARKER_GREY`
|
|
||||||
* - `LIGHT_GREY`
|
|
||||||
* - `DARK_NAVY`
|
|
||||||
* - `BLURPLE`
|
|
||||||
* - `GREYPLE`
|
|
||||||
* - `DARK_BUT_NOT_BLACK`
|
|
||||||
* - `NOT_QUITE_BLACK`
|
|
||||||
* - `RANDOM`
|
|
||||||
* @typedef {string|number|number[]} ColorResolvable
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -603,6 +582,17 @@ class Util extends null {
|
|||||||
filter.isDefault = true;
|
filter.isDefault = true;
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves the maximum time a guild's thread channels should automatcally archive in case of no recent activity.
|
||||||
|
* @param {Guild} guild The guild to resolve this limit from.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
static resolveAutoArchiveMaxLimit({ features }) {
|
||||||
|
if (features.includes('SEVEN_DAY_THREAD_ARCHIVE')) return 10080;
|
||||||
|
if (features.includes('THREE_DAY_THREAD_ARCHIVE')) return 4320;
|
||||||
|
return 1440;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Util;
|
module.exports = Util;
|
||||||
|
|||||||
20
typings/enums.d.ts
vendored
20
typings/enums.d.ts
vendored
@@ -27,6 +27,7 @@ export const enum ApplicationCommandOptionTypes {
|
|||||||
ROLE = 8,
|
ROLE = 8,
|
||||||
MENTIONABLE = 9,
|
MENTIONABLE = 9,
|
||||||
NUMBER = 10,
|
NUMBER = 10,
|
||||||
|
ATTACHMENT = 11,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum ApplicationCommandPermissionTypes {
|
export const enum ApplicationCommandPermissionTypes {
|
||||||
@@ -47,6 +48,7 @@ export const enum ChannelTypes {
|
|||||||
GUILD_PUBLIC_THREAD = 11,
|
GUILD_PUBLIC_THREAD = 11,
|
||||||
GUILD_PRIVATE_THREAD = 12,
|
GUILD_PRIVATE_THREAD = 12,
|
||||||
GUILD_STAGE_VOICE = 13,
|
GUILD_STAGE_VOICE = 13,
|
||||||
|
GUILD_DIRECTORY = 14,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum MessageTypes {
|
export const enum MessageTypes {
|
||||||
@@ -110,6 +112,7 @@ export const enum InteractionResponseTypes {
|
|||||||
DEFERRED_MESSAGE_UPDATE = 6,
|
DEFERRED_MESSAGE_UPDATE = 6,
|
||||||
UPDATE_MESSAGE = 7,
|
UPDATE_MESSAGE = 7,
|
||||||
APPLICATION_COMMAND_AUTOCOMPLETE_RESULT = 8,
|
APPLICATION_COMMAND_AUTOCOMPLETE_RESULT = 8,
|
||||||
|
MODAL = 9,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum InteractionTypes {
|
export const enum InteractionTypes {
|
||||||
@@ -117,6 +120,7 @@ export const enum InteractionTypes {
|
|||||||
APPLICATION_COMMAND = 2,
|
APPLICATION_COMMAND = 2,
|
||||||
MESSAGE_COMPONENT = 3,
|
MESSAGE_COMPONENT = 3,
|
||||||
APPLICATION_COMMAND_AUTOCOMPLETE = 4,
|
APPLICATION_COMMAND_AUTOCOMPLETE = 4,
|
||||||
|
MODAL_SUBMIT = 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum InviteTargetType {
|
export const enum InviteTargetType {
|
||||||
@@ -141,6 +145,12 @@ export const enum MessageComponentTypes {
|
|||||||
ACTION_ROW = 1,
|
ACTION_ROW = 1,
|
||||||
BUTTON = 2,
|
BUTTON = 2,
|
||||||
SELECT_MENU = 3,
|
SELECT_MENU = 3,
|
||||||
|
TEXT_INPUT = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const enum ModalComponentTypes {
|
||||||
|
ACTION_ROW = 1,
|
||||||
|
TEXT_INPUT = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum MFALevels {
|
export const enum MFALevels {
|
||||||
@@ -183,6 +193,11 @@ export const enum StickerTypes {
|
|||||||
GUILD = 2,
|
GUILD = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const enum TextInputStyles {
|
||||||
|
SHORT = 1,
|
||||||
|
PARAGRAPH = 2,
|
||||||
|
}
|
||||||
|
|
||||||
export const enum VerificationLevels {
|
export const enum VerificationLevels {
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
LOW = 1,
|
LOW = 1,
|
||||||
@@ -191,6 +206,11 @@ export const enum VerificationLevels {
|
|||||||
VERY_HIGH = 4,
|
VERY_HIGH = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const enum VideoQualityModes {
|
||||||
|
AUTO = 1,
|
||||||
|
FULL = 2,
|
||||||
|
}
|
||||||
|
|
||||||
export const enum WebhookTypes {
|
export const enum WebhookTypes {
|
||||||
Incoming = 1,
|
Incoming = 1,
|
||||||
'Channel Follower' = 2,
|
'Channel Follower' = 2,
|
||||||
|
|||||||
651
typings/index.d.ts
vendored
651
typings/index.d.ts
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
|||||||
import type { ChildProcess } from 'child_process';
|
import type { ChildProcess } from 'child_process';
|
||||||
|
import type { Worker } from 'worker_threads';
|
||||||
import type {
|
import type {
|
||||||
APIInteractionGuildMember,
|
APIInteractionGuildMember,
|
||||||
APIMessage,
|
APIMessage,
|
||||||
@@ -93,9 +94,13 @@ import {
|
|||||||
MessageActionRowComponent,
|
MessageActionRowComponent,
|
||||||
MessageSelectMenu,
|
MessageSelectMenu,
|
||||||
PartialDMChannel,
|
PartialDMChannel,
|
||||||
|
InteractionResponseFields,
|
||||||
|
GuildBan,
|
||||||
|
GuildBanManager,
|
||||||
} from '.';
|
} from '.';
|
||||||
import type { ApplicationCommandOptionTypes } from './enums';
|
import type { ApplicationCommandOptionTypes } from './enums';
|
||||||
import { expectAssignable, expectDeprecated, expectNotAssignable, expectNotType, expectType } from 'tsd';
|
import { expectAssignable, expectDeprecated, expectNotAssignable, expectNotType, expectType } from 'tsd';
|
||||||
|
import type { ContextMenuCommandBuilder, SlashCommandBuilder } from '@discordjs/builders';
|
||||||
|
|
||||||
// Test type transformation:
|
// Test type transformation:
|
||||||
declare const serialize: <T>(value: T) => Serialized<T>;
|
declare const serialize: <T>(value: T) => Serialized<T>;
|
||||||
@@ -124,6 +129,9 @@ const testUserId = '987654321098765432'; // example id
|
|||||||
const globalCommandId = '123456789012345678'; // example id
|
const globalCommandId = '123456789012345678'; // example id
|
||||||
const guildCommandId = '234567890123456789'; // example id
|
const guildCommandId = '234567890123456789'; // example id
|
||||||
|
|
||||||
|
declare const slashCommandBuilder: SlashCommandBuilder;
|
||||||
|
declare const contextMenuCommandBuilder: ContextMenuCommandBuilder;
|
||||||
|
|
||||||
client.on('ready', async () => {
|
client.on('ready', async () => {
|
||||||
console.log(`Client is logged in as ${client.user!.tag} and ready!`);
|
console.log(`Client is logged in as ${client.user!.tag} and ready!`);
|
||||||
|
|
||||||
@@ -140,6 +148,21 @@ client.on('ready', async () => {
|
|||||||
const guildCommandFromGlobal = await client.application?.commands.fetch(guildCommandId, { guildId: testGuildId });
|
const guildCommandFromGlobal = await client.application?.commands.fetch(guildCommandId, { guildId: testGuildId });
|
||||||
const guildCommandFromGuild = await client.guilds.cache.get(testGuildId)?.commands.fetch(guildCommandId);
|
const guildCommandFromGuild = await client.guilds.cache.get(testGuildId)?.commands.fetch(guildCommandId);
|
||||||
|
|
||||||
|
await client.application?.commands.create(slashCommandBuilder);
|
||||||
|
await client.application?.commands.create(contextMenuCommandBuilder);
|
||||||
|
await guild.commands.create(slashCommandBuilder);
|
||||||
|
await guild.commands.create(contextMenuCommandBuilder);
|
||||||
|
|
||||||
|
await client.application?.commands.edit(globalCommandId, slashCommandBuilder);
|
||||||
|
await client.application?.commands.edit(globalCommandId, contextMenuCommandBuilder);
|
||||||
|
await guild.commands.edit(guildCommandId, slashCommandBuilder);
|
||||||
|
await guild.commands.edit(guildCommandId, contextMenuCommandBuilder);
|
||||||
|
|
||||||
|
await client.application?.commands.edit(globalCommandId, { defaultMemberPermissions: null });
|
||||||
|
await globalCommand?.edit({ defaultMemberPermissions: null });
|
||||||
|
await globalCommand?.setDefaultMemberPermissions(null);
|
||||||
|
await guildCommandFromGlobal?.edit({ dmPermission: false });
|
||||||
|
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
await client.guilds.cache.get(testGuildId)?.commands.fetch(guildCommandId, { guildId: testGuildId });
|
await client.guilds.cache.get(testGuildId)?.commands.fetch(guildCommandId, { guildId: testGuildId });
|
||||||
|
|
||||||
@@ -678,6 +701,8 @@ client.on('interaction', async interaction => {
|
|||||||
|
|
||||||
void new MessageActionRow();
|
void new MessageActionRow();
|
||||||
|
|
||||||
|
void new MessageActionRow({});
|
||||||
|
|
||||||
const button = new MessageButton();
|
const button = new MessageButton();
|
||||||
|
|
||||||
const actionRow = new MessageActionRow({ components: [button] });
|
const actionRow = new MessageActionRow({ components: [button] });
|
||||||
@@ -687,9 +712,6 @@ client.on('interaction', async interaction => {
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
interaction.reply({ content: 'Hi!', components: [[button]] });
|
interaction.reply({ content: 'Hi!', components: [[button]] });
|
||||||
|
|
||||||
// @ts-expect-error
|
|
||||||
void new MessageActionRow({});
|
|
||||||
|
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
await interaction.reply({ content: 'Hi!', components: [button] });
|
await interaction.reply({ content: 'Hi!', components: [button] });
|
||||||
|
|
||||||
@@ -768,9 +790,10 @@ declare const guildMember: GuildMember;
|
|||||||
|
|
||||||
// Test whether the structures implement send
|
// Test whether the structures implement send
|
||||||
expectType<TextBasedChannelFields['send']>(dmChannel.send);
|
expectType<TextBasedChannelFields['send']>(dmChannel.send);
|
||||||
expectType<ThreadChannel>(threadChannel);
|
expectType<TextBasedChannelFields['send']>(threadChannel.send);
|
||||||
expectType<NewsChannel>(newsChannel);
|
expectType<TextBasedChannelFields['send']>(newsChannel.send);
|
||||||
expectType<TextChannel>(textChannel);
|
expectType<TextBasedChannelFields['send']>(textChannel.send);
|
||||||
|
expectType<TextBasedChannelFields['send']>(voiceChannel.send);
|
||||||
expectAssignable<PartialTextBasedChannelFields>(user);
|
expectAssignable<PartialTextBasedChannelFields>(user);
|
||||||
expectAssignable<PartialTextBasedChannelFields>(guildMember);
|
expectAssignable<PartialTextBasedChannelFields>(guildMember);
|
||||||
|
|
||||||
@@ -778,6 +801,7 @@ expectType<Message | null>(dmChannel.lastMessage);
|
|||||||
expectType<Message | null>(threadChannel.lastMessage);
|
expectType<Message | null>(threadChannel.lastMessage);
|
||||||
expectType<Message | null>(newsChannel.lastMessage);
|
expectType<Message | null>(newsChannel.lastMessage);
|
||||||
expectType<Message | null>(textChannel.lastMessage);
|
expectType<Message | null>(textChannel.lastMessage);
|
||||||
|
expectType<Message | null>(voiceChannel.lastMessage);
|
||||||
|
|
||||||
expectDeprecated(storeChannel.clone());
|
expectDeprecated(storeChannel.clone());
|
||||||
expectDeprecated(categoryChannel.createChannel('Store', { type: 'GUILD_STORE' }));
|
expectDeprecated(categoryChannel.createChannel('Store', { type: 'GUILD_STORE' }));
|
||||||
@@ -827,6 +851,14 @@ declare const applicationCommandManager: ApplicationCommandManager;
|
|||||||
expectType<Promise<Collection<Snowflake, ApplicationCommand>>>(
|
expectType<Promise<Collection<Snowflake, ApplicationCommand>>>(
|
||||||
applicationCommandManager.set([applicationCommandData], '0'),
|
applicationCommandManager.set([applicationCommandData], '0'),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
applicationCommandManager.create({
|
||||||
|
name: 'yeet',
|
||||||
|
description: 'abc',
|
||||||
|
defaultMemberPermissions: 1n,
|
||||||
|
dmPermission: false,
|
||||||
|
type: 'CHAT_INPUT',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
declare const applicationNonChoiceOptionData: ApplicationCommandOptionData & {
|
declare const applicationNonChoiceOptionData: ApplicationCommandOptionData & {
|
||||||
@@ -867,6 +899,8 @@ declare const guildChannelManager: GuildChannelManager;
|
|||||||
{
|
{
|
||||||
type AnyChannel = TextChannel | VoiceChannel | CategoryChannel | NewsChannel | StoreChannel | StageChannel;
|
type AnyChannel = TextChannel | VoiceChannel | CategoryChannel | NewsChannel | StoreChannel | StageChannel;
|
||||||
|
|
||||||
|
expectType<Promise<TextChannel>>(guildChannelManager.create('name'));
|
||||||
|
expectType<Promise<TextChannel>>(guildChannelManager.create('name', {}));
|
||||||
expectType<Promise<VoiceChannel>>(guildChannelManager.create('name', { type: 'GUILD_VOICE' }));
|
expectType<Promise<VoiceChannel>>(guildChannelManager.create('name', { type: 'GUILD_VOICE' }));
|
||||||
expectType<Promise<CategoryChannel>>(guildChannelManager.create('name', { type: 'GUILD_CATEGORY' }));
|
expectType<Promise<CategoryChannel>>(guildChannelManager.create('name', { type: 'GUILD_CATEGORY' }));
|
||||||
expectType<Promise<TextChannel>>(guildChannelManager.create('name', { type: 'GUILD_TEXT' }));
|
expectType<Promise<TextChannel>>(guildChannelManager.create('name', { type: 'GUILD_TEXT' }));
|
||||||
@@ -889,6 +923,20 @@ expectType<Promise<Collection<Snowflake, GuildEmoji>>>(guildEmojiManager.fetch()
|
|||||||
expectType<Promise<Collection<Snowflake, GuildEmoji>>>(guildEmojiManager.fetch(undefined, {}));
|
expectType<Promise<Collection<Snowflake, GuildEmoji>>>(guildEmojiManager.fetch(undefined, {}));
|
||||||
expectType<Promise<GuildEmoji>>(guildEmojiManager.fetch('0'));
|
expectType<Promise<GuildEmoji>>(guildEmojiManager.fetch('0'));
|
||||||
|
|
||||||
|
declare const guildBanManager: GuildBanManager;
|
||||||
|
{
|
||||||
|
expectType<Promise<GuildBan>>(guildBanManager.fetch('1234567890'));
|
||||||
|
expectType<Promise<GuildBan>>(guildBanManager.fetch({ user: '1234567890' }));
|
||||||
|
expectType<Promise<GuildBan>>(guildBanManager.fetch({ user: '1234567890', cache: true, force: false }));
|
||||||
|
expectType<Promise<Collection<Snowflake, GuildBan>>>(guildBanManager.fetch());
|
||||||
|
expectType<Promise<Collection<Snowflake, GuildBan>>>(guildBanManager.fetch({}));
|
||||||
|
expectType<Promise<Collection<Snowflake, GuildBan>>>(guildBanManager.fetch({ limit: 100, before: '1234567890' }));
|
||||||
|
// @ts-expect-error
|
||||||
|
guildBanManager.fetch({ cache: true, force: false });
|
||||||
|
// @ts-expect-error
|
||||||
|
guildBanManager.fetch({ user: '1234567890', after: '1234567890', cache: true, force: false });
|
||||||
|
}
|
||||||
|
|
||||||
declare const typing: Typing;
|
declare const typing: Typing;
|
||||||
expectType<PartialUser>(typing.user);
|
expectType<PartialUser>(typing.user);
|
||||||
if (typing.user.partial) expectType<null>(typing.user.username);
|
if (typing.user.partial) expectType<null>(typing.user.username);
|
||||||
@@ -942,19 +990,45 @@ expectDeprecated(sticker.deleted);
|
|||||||
// Test interactions
|
// Test interactions
|
||||||
declare const interaction: Interaction;
|
declare const interaction: Interaction;
|
||||||
declare const booleanValue: boolean;
|
declare const booleanValue: boolean;
|
||||||
if (interaction.inGuild()) expectType<Snowflake>(interaction.guildId);
|
if (interaction.inGuild()) {
|
||||||
|
expectType<Snowflake>(interaction.guildId);
|
||||||
|
} else {
|
||||||
|
expectType<Snowflake | null>(interaction.guildId);
|
||||||
|
}
|
||||||
|
|
||||||
|
client.on('interactionCreate', interaction => {
|
||||||
|
// This is for testing never type resolution
|
||||||
|
if (!interaction.inGuild()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interaction.inRawGuild()) {
|
||||||
|
expectNotType<never>(interaction);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interaction.inCachedGuild()) {
|
||||||
|
expectNotType<never>(interaction);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
client.on('interactionCreate', async interaction => {
|
client.on('interactionCreate', async interaction => {
|
||||||
if (interaction.inCachedGuild()) {
|
if (interaction.inCachedGuild()) {
|
||||||
expectAssignable<GuildMember>(interaction.member);
|
expectAssignable<GuildMember>(interaction.member);
|
||||||
expectNotType<CommandInteraction<'cached'>>(interaction);
|
expectNotType<CommandInteraction<'cached'>>(interaction);
|
||||||
expectAssignable<Interaction>(interaction);
|
expectAssignable<Interaction>(interaction);
|
||||||
|
expectType<string>(interaction.guildLocale);
|
||||||
} else if (interaction.inRawGuild()) {
|
} else if (interaction.inRawGuild()) {
|
||||||
expectAssignable<APIInteractionGuildMember>(interaction.member);
|
expectAssignable<APIInteractionGuildMember>(interaction.member);
|
||||||
expectNotAssignable<Interaction<'cached'>>(interaction);
|
expectNotAssignable<Interaction<'cached'>>(interaction);
|
||||||
|
expectType<string>(interaction.guildLocale);
|
||||||
|
} else if (interaction.inGuild()) {
|
||||||
|
expectType<string>(interaction.guildLocale);
|
||||||
} else {
|
} else {
|
||||||
expectType<APIInteractionGuildMember | GuildMember | null>(interaction.member);
|
expectType<APIInteractionGuildMember | GuildMember | null>(interaction.member);
|
||||||
expectNotAssignable<Interaction<'cached'>>(interaction);
|
expectNotAssignable<Interaction<'cached'>>(interaction);
|
||||||
|
expectType<string | null>(interaction.guildId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interaction.isContextMenu()) {
|
if (interaction.isContextMenu()) {
|
||||||
@@ -1117,12 +1191,22 @@ client.on('interactionCreate', async interaction => {
|
|||||||
expectType<string | null>(interaction.options.getSubcommandGroup(booleanValue));
|
expectType<string | null>(interaction.options.getSubcommandGroup(booleanValue));
|
||||||
expectType<string | null>(interaction.options.getSubcommandGroup(false));
|
expectType<string | null>(interaction.options.getSubcommandGroup(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (interaction.isRepliable()) {
|
||||||
|
expectAssignable<InteractionResponseFields>(interaction);
|
||||||
|
interaction.reply('test');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interaction.isCommand() && interaction.isRepliable()) {
|
||||||
|
expectAssignable<CommandInteraction>(interaction);
|
||||||
|
expectAssignable<InteractionResponseFields>(interaction);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
declare const shard: Shard;
|
declare const shard: Shard;
|
||||||
|
|
||||||
shard.on('death', process => {
|
shard.on('death', process => {
|
||||||
expectType<ChildProcess>(process);
|
expectType<ChildProcess | Worker>(process);
|
||||||
});
|
});
|
||||||
|
|
||||||
declare const webSocketShard: WebSocketShard;
|
declare const webSocketShard: WebSocketShard;
|
||||||
@@ -1238,10 +1322,16 @@ declare const GuildBasedChannel: GuildBasedChannel;
|
|||||||
declare const NonThreadGuildBasedChannel: NonThreadGuildBasedChannel;
|
declare const NonThreadGuildBasedChannel: NonThreadGuildBasedChannel;
|
||||||
declare const GuildTextBasedChannel: GuildTextBasedChannel;
|
declare const GuildTextBasedChannel: GuildTextBasedChannel;
|
||||||
|
|
||||||
expectType<DMChannel | PartialDMChannel | NewsChannel | TextChannel | ThreadChannel>(TextBasedChannel);
|
expectType<DMChannel | PartialDMChannel | NewsChannel | TextChannel | ThreadChannel | VoiceChannel>(TextBasedChannel);
|
||||||
expectType<'DM' | 'GUILD_NEWS' | 'GUILD_TEXT' | 'GUILD_PUBLIC_THREAD' | 'GUILD_PRIVATE_THREAD' | 'GUILD_NEWS_THREAD'>(
|
expectType<
|
||||||
TextBasedChannelTypes,
|
| 'DM'
|
||||||
);
|
| 'GUILD_NEWS'
|
||||||
|
| 'GUILD_TEXT'
|
||||||
|
| 'GUILD_PUBLIC_THREAD'
|
||||||
|
| 'GUILD_PRIVATE_THREAD'
|
||||||
|
| 'GUILD_NEWS_THREAD'
|
||||||
|
| 'GUILD_VOICE'
|
||||||
|
>(TextBasedChannelTypes);
|
||||||
expectType<StageChannel | VoiceChannel>(VoiceBasedChannel);
|
expectType<StageChannel | VoiceChannel>(VoiceBasedChannel);
|
||||||
expectType<CategoryChannel | NewsChannel | StageChannel | StoreChannel | TextChannel | ThreadChannel | VoiceChannel>(
|
expectType<CategoryChannel | NewsChannel | StageChannel | StoreChannel | TextChannel | ThreadChannel | VoiceChannel>(
|
||||||
GuildBasedChannel,
|
GuildBasedChannel,
|
||||||
@@ -1249,4 +1339,4 @@ expectType<CategoryChannel | NewsChannel | StageChannel | StoreChannel | TextCha
|
|||||||
expectType<CategoryChannel | NewsChannel | StageChannel | StoreChannel | TextChannel | VoiceChannel>(
|
expectType<CategoryChannel | NewsChannel | StageChannel | StoreChannel | TextChannel | VoiceChannel>(
|
||||||
NonThreadGuildBasedChannel,
|
NonThreadGuildBasedChannel,
|
||||||
);
|
);
|
||||||
expectType<NewsChannel | TextChannel | ThreadChannel>(GuildTextBasedChannel);
|
expectType<NewsChannel | TextChannel | ThreadChannel | VoiceChannel>(GuildTextBasedChannel);
|
||||||
|
|||||||
10
typings/rawDataTypes.d.ts
vendored
10
typings/rawDataTypes.d.ts
vendored
@@ -76,8 +76,13 @@ import {
|
|||||||
RESTPostAPIWebhookWithTokenJSONBody,
|
RESTPostAPIWebhookWithTokenJSONBody,
|
||||||
Snowflake,
|
Snowflake,
|
||||||
APIGuildScheduledEvent,
|
APIGuildScheduledEvent,
|
||||||
|
APIActionRowComponent,
|
||||||
|
APITextInputComponent,
|
||||||
|
APIModalActionRowComponent,
|
||||||
|
APIModalSubmitInteraction,
|
||||||
} from 'discord-api-types/v9';
|
} from 'discord-api-types/v9';
|
||||||
import { GuildChannel, Guild, PermissionOverwrites } from '.';
|
import { GuildChannel, Guild, PermissionOverwrites, InteractionType } from '.';
|
||||||
|
import type { InteractionTypes, MessageComponentTypes } from './enums';
|
||||||
|
|
||||||
export type RawActivityData = GatewayActivity;
|
export type RawActivityData = GatewayActivity;
|
||||||
|
|
||||||
@@ -141,6 +146,9 @@ export type RawMessageComponentInteractionData = APIMessageComponentInteraction;
|
|||||||
export type RawMessageButtonInteractionData = APIMessageButtonInteractionData;
|
export type RawMessageButtonInteractionData = APIMessageButtonInteractionData;
|
||||||
export type RawMessageSelectMenuInteractionData = APIMessageSelectMenuInteractionData;
|
export type RawMessageSelectMenuInteractionData = APIMessageSelectMenuInteractionData;
|
||||||
|
|
||||||
|
export type RawTextInputComponentData = APITextInputComponent;
|
||||||
|
export type RawModalSubmitInteractionData = APIModalSubmitInteraction;
|
||||||
|
|
||||||
export type RawInviteData =
|
export type RawInviteData =
|
||||||
| APIExtendedInvite
|
| APIExtendedInvite
|
||||||
| APIInvite
|
| APIInvite
|
||||||
|
|||||||
Reference in New Issue
Block a user