mirror of
https://github.com/discordjs/discord.js.git
synced 2026-05-23 03:50:09 +00:00
Compare commits
166 Commits
@discordjs
...
13.13.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f1735d50a | ||
|
|
fd494a385e | ||
|
|
b586df884b | ||
|
|
0188e36283 | ||
|
|
84d34dc258 | ||
|
|
7737bbe2fe | ||
|
|
61fa6f45b4 | ||
|
|
0afa405f5a | ||
|
|
eed293f893 | ||
|
|
86329ad66f | ||
|
|
69d71e967e | ||
|
|
a7dc40f1a8 | ||
|
|
32cdaff7eb | ||
|
|
123d0f1aca | ||
|
|
d69529e3fe | ||
|
|
c2968b58f9 | ||
|
|
428798374f | ||
|
|
cf3c7a7c54 | ||
|
|
a941cb6ec5 | ||
|
|
6854df4218 | ||
|
|
35f6dadebf | ||
|
|
1779e1ba7e | ||
|
|
11d010f177 | ||
|
|
b01c81dd72 | ||
|
|
f0d42644df | ||
|
|
64575195b5 | ||
|
|
5115de9862 | ||
|
|
546ac43911 | ||
|
|
56e67185fc | ||
|
|
649058055a | ||
|
|
4ec3355961 | ||
|
|
ca662b4de8 | ||
|
|
98846cf863 | ||
|
|
0e0851aa18 | ||
|
|
eecc50bfda | ||
|
|
caf6f66073 | ||
|
|
c312da795e | ||
|
|
312923d370 | ||
|
|
8a6588a132 | ||
|
|
ea117bfb7e | ||
|
|
8d6a55d2c7 | ||
|
|
5ef30a0173 | ||
|
|
8f94a9ca2f | ||
|
|
fcd52d7fc6 | ||
|
|
f4e81330bf | ||
|
|
e6ee7d8374 | ||
|
|
56177998c5 | ||
|
|
ca68fc3f6b | ||
|
|
a507ed9590 | ||
|
|
f0c0166814 | ||
|
|
10b12ccea6 | ||
|
|
526ea74e66 | ||
|
|
b6f48ec84a | ||
|
|
11d69491e0 | ||
|
|
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,
|
||||
"always",
|
||||
["chore", "build", "ci", "docs", "feat", "fix", "perf", "refactor", "revert", "style", "test", "types", "typings"]
|
||||
]
|
||||
],
|
||||
"scope-case": [0]
|
||||
}
|
||||
}
|
||||
|
||||
11
.github/.kodiak.toml
vendored
Normal file
11
.github/.kodiak.toml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
version = 1
|
||||
|
||||
[merge]
|
||||
require_automerge_label = false
|
||||
blocking_labels = ['blocked']
|
||||
method = 'squash'
|
||||
|
||||
[merge.message]
|
||||
title = 'pull_request_title'
|
||||
strip_html_comments = true
|
||||
include_coauthors = true
|
||||
8
.github/auto_assign.yml
vendored
Normal file
8
.github/auto_assign.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
addReviewers: true
|
||||
reviewers:
|
||||
- iCrawl
|
||||
- SpaceEEC
|
||||
- kyranet
|
||||
- vladfrangu
|
||||
numberOfReviewers: 0
|
||||
runOnDraft: true
|
||||
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
|
||||
15
.github/labeler.yml
vendored
Normal file
15
.github/labeler.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
apps:guide:
|
||||
- apps/guide/*
|
||||
- apps/guide/**/*
|
||||
apps:website:
|
||||
- apps/website/*
|
||||
- apps/website/**/*
|
||||
packages:discord.js:
|
||||
- scripts/*
|
||||
- scripts/**/*
|
||||
- src/*
|
||||
- src/**/*
|
||||
- test/*
|
||||
- test/**/*
|
||||
- typings/*
|
||||
- typings/**/*
|
||||
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
|
||||
17
.github/workflows/pr-triage.yml
vendored
Normal file
17
.github/workflows/pr-triage.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
name: 'PR Triage'
|
||||
on:
|
||||
pull_request_target:
|
||||
jobs:
|
||||
pr-triage:
|
||||
name: PR Triage
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Automatically label PR
|
||||
uses: actions/labeler@v4
|
||||
with:
|
||||
repo-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
sync-labels: true
|
||||
|
||||
- name: Automatically assign reviewers
|
||||
if: github.event.action == 'opened'
|
||||
uses: kentaro-m/auto-assign-action@v1.2.4
|
||||
30
.github/workflows/publish-release.yml
vendored
Normal file
30
.github/workflows/publish-release.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: Publish Release
|
||||
on:
|
||||
release:
|
||||
types: [released]
|
||||
jobs:
|
||||
npm-publish:
|
||||
name: npm publish
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
if: github.repository_owner == 'discordjs'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install node.js v16
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
registry-url: https://registry.npmjs.org/
|
||||
cache: npm
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci --ignore-scripts
|
||||
|
||||
- name: Publish package (v13)
|
||||
run: npm publish --tag v13-lts
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -28,3 +28,5 @@ docs/docs.json
|
||||
.tmp/
|
||||
.idea/
|
||||
.DS_Store
|
||||
.yarn/
|
||||
.turbo/
|
||||
|
||||
351
CHANGELOG.md
351
CHANGELOG.md
@@ -1,14 +1,294 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
# [13.5.0](https://github.com/discordjs/discord.js/compare/13.4.0...13.5.0) - (2021-12-29)
|
||||
# [13.13.0](https://github.com/discordjs/discord.js/compare/13.12.0...13.13.0) - (2023-02-21)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- Minor forums cleanup (#9033) ([eed293f](https://github.com/discordjs/discord.js/commit/eed293f893da2ea00cc81c49b636b98066513c4b))
|
||||
- **InteractionResponses:** Spell `messages` correctly (#9080) ([123d0f1](https://github.com/discordjs/discord.js/commit/123d0f1aca109a703fd52fcff82b47cc02d57edd))
|
||||
- **ThreadChannel:** `reason` as second parameter (#9023) ([a941cb6](https://github.com/discordjs/discord.js/commit/a941cb6ec58d558016ddd19424b45f765b0536ef))
|
||||
- Import errors correctly (#9030) ([6457519](https://github.com/discordjs/discord.js/commit/64575195b511fb3e5353a192d4105326b534bcde))
|
||||
- **websocketshard:** Backport zombie connection fix (#9003) ([56e6718](https://github.com/discordjs/discord.js/commit/56e67185fc346e04e5d1adad8d7bfb932336cf93))
|
||||
- **Util:** Flatten ignoring certain fields (v13) (#8936) ([4ec3355](https://github.com/discordjs/discord.js/commit/4ec3355961b7105a417e8854ae72f4ee302690f9))
|
||||
- Backport allow deletion of ephemeral messages to v13 (#8811) ([98846cf](https://github.com/discordjs/discord.js/commit/98846cf863c76348e730e6944d4b7390148aa258))
|
||||
- **Activity:** Fix equals() not checking for differing emoji (v13) (#8842) ([eecc50b](https://github.com/discordjs/discord.js/commit/eecc50bfda89cd240dd20539234f7fc2e975daa6))
|
||||
- **escapeMarkdown:** Fix double escaping (v13) (#8799) ([caf6f66](https://github.com/discordjs/discord.js/commit/caf6f66073d6681e99dc02af3e0bdd6529366ddb))
|
||||
- Fixed TS 4.8 compatibility (#8601) ([e6ee7d8](https://github.com/discordjs/discord.js/commit/e6ee7d8374ddc157037c258b63225384c154a2e6))
|
||||
|
||||
## Documentation
|
||||
|
||||
- **ThreadEditOptions:** Move info tag back to `invitable` (#9021) ([cf3c7a7](https://github.com/discordjs/discord.js/commit/cf3c7a7c545e692c56f09344d846215fe6692587))
|
||||
- Add missing `@extends` (#9028) ([1779e1b](https://github.com/discordjs/discord.js/commit/1779e1ba7e9bf7aad9a853097a841a36416d8ce6))
|
||||
- Update UserContextMenu documentation v13 (#8721) ([ea117bf](https://github.com/discordjs/discord.js/commit/ea117bfb7e04e1103eaf24208c06979ce8493129))
|
||||
- Update misleading `Client#guildMemberAvailable` event description (v13) (#8627) ([fcd52d7](https://github.com/discordjs/discord.js/commit/fcd52d7fc6b195b50bf6e5eb6e670fbd1ba5fd59))
|
||||
|
||||
## Features
|
||||
|
||||
- **WebSocketShard:** V13 add resume url (#9078) ([0188e36](https://github.com/discordjs/discord.js/commit/0188e362836bd6350a574595dc61d2c8ab3f256a))
|
||||
- V13 `guildAuditLogEntryCreate` event (#9092) ([84d34dc](https://github.com/discordjs/discord.js/commit/84d34dc258ca2a0953f8c2a0212d8459c7c16b84))
|
||||
- **Constants:** Add auto moderation events to WSEvents (#9102) ([61fa6f4](https://github.com/discordjs/discord.js/commit/61fa6f45b43ce5dec79b9cac9398b4e619190542))
|
||||
- Role subscriptions (#9040) ([0afa405](https://github.com/discordjs/discord.js/commit/0afa405f5a967ed5d82cfeffedc84d444c034924))
|
||||
- **GuildChannelManager:** Add `addFollower` (#9050) ([86329ad](https://github.com/discordjs/discord.js/commit/86329ad66fb5055c49893e69bff4c6ba2d412d29))
|
||||
- **Guild:** Add `INVITES_DISABLED` feature support (#9051) ([69d71e9](https://github.com/discordjs/discord.js/commit/69d71e967e12b83dd6d9accfb604cdd81d1aac09))
|
||||
- **ClientApplication:** Add role connections (#9072) ([a7dc40f](https://github.com/discordjs/discord.js/commit/a7dc40f1a8a587b58c590008d11c5543637d6341))
|
||||
- **Webhook:** Add `channel` getter (#9074) ([32cdaff](https://github.com/discordjs/discord.js/commit/32cdaff7eb29cb60a721ee5967875ec64bef0e8a))
|
||||
- **GuildMember:** Add `flags` (#9098) ([d69529e](https://github.com/discordjs/discord.js/commit/d69529e3fe4266d14d5d526b95ad6b57030d5b71))
|
||||
- `applicationCommandPermissionsUpdate` event (#9121) ([c2968b5](https://github.com/discordjs/discord.js/commit/c2968b58f9c6a176ecdae4e2e5c3a95e9421c23b))
|
||||
- Backport automod (#8886) ([4287983](https://github.com/discordjs/discord.js/commit/428798374f4c3c2128b844d476627762dd45edf4))
|
||||
- **GuildAuditLogs:** Support `after` (#9012) ([f0d4264](https://github.com/discordjs/discord.js/commit/f0d42644dfeec1594baac7817bb05b0aef2be6f0))
|
||||
- Backport guild forum support to v13 (#8651) ([546ac43](https://github.com/discordjs/discord.js/commit/546ac439115f4017f01e0c02dee2ff80b789c28b))
|
||||
- Add `Message#bulkDeletable` (v13) (#8761) ([ca662b4](https://github.com/discordjs/discord.js/commit/ca662b4de82d71bf8931e277544465cb3b66062c))
|
||||
- **InteractionResponses:** Add message parameter (v13) (#8838) ([0e0851a](https://github.com/discordjs/discord.js/commit/0e0851aa18d873925a3b41c47665a15fde440939))
|
||||
- **Util:** Backport `escapeMarkdown` PRs to v13 (#8703) ([8a6588a](https://github.com/discordjs/discord.js/commit/8a6588a13203120b0d185732cd7db7ecdb9f00f7))
|
||||
- **GuildBanManager:** Add `deleteMessageSeconds` (#8575) ([ca68fc3](https://github.com/discordjs/discord.js/commit/ca68fc3f6b5dbe8708d065ffea5a89b23d4db757))
|
||||
|
||||
## Refactor
|
||||
|
||||
- Move `me` and add `fetchMe()` (#9029) ([b01c81d](https://github.com/discordjs/discord.js/commit/b01c81dd72b71e6a5241dc10b72793596c7cbebf))
|
||||
|
||||
## Typings
|
||||
|
||||
- **ThreadEditOptions:** Add `appliedTags` (#9022) ([6854df4](https://github.com/discordjs/discord.js/commit/6854df42183ba6fccbff3a0366170557e0152e66))
|
||||
- **widget:** Add missing `name` (#9031) ([35f6dad](https://github.com/discordjs/discord.js/commit/35f6dadebfce9ad60e360b5317267e256571a0ae))
|
||||
- Swap message reaction and emoji identifier types (#8970) ([6490580](https://github.com/discordjs/discord.js/commit/649058055a3159277a19e3173c115a67226f0ee0))
|
||||
- **GuildChannelManager:** Correct fetch return type (v13) (#8551) ([f4e8133](https://github.com/discordjs/discord.js/commit/f4e81330bf35bac0d8317dbb170312422df432fa))
|
||||
|
||||
# [13.12.0](https://github.com/discordjs/discord.js/compare/13.11.0...13.12.0) - (2022-10-10)
|
||||
|
||||
## Documentation
|
||||
|
||||
- Update UserContextMenu documentation v13 (#8721) ([ea117bf](https://github.com/discordjs/discord.js/commit/ea117bfb7e04e1103eaf24208c06979ce8493129))
|
||||
|
||||
## Features
|
||||
|
||||
- **Util:** Backport `escapeMarkdown` PRs to v13 (#8703) ([8a6588a](https://github.com/discordjs/discord.js/commit/8a6588a13203120b0d185732cd7db7ecdb9f00f7))
|
||||
|
||||
# [13.11.0](https://github.com/discordjs/discord.js/compare/13.10.3...13.11.0) - (2022-09-15)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- Fixed TS 4.8 compatibility (#8601) ([e6ee7d8](https://github.com/discordjs/discord.js/commit/e6ee7d8374ddc157037c258b63225384c154a2e6))
|
||||
|
||||
## Documentation
|
||||
|
||||
- Update misleading `Client#guildMemberAvailable` event description (v13) (#8627) ([fcd52d7](https://github.com/discordjs/discord.js/commit/fcd52d7fc6b195b50bf6e5eb6e670fbd1ba5fd59))
|
||||
|
||||
## Features
|
||||
|
||||
- **GuildBanManager:** Add `deleteMessageSeconds` (#8575) ([ca68fc3](https://github.com/discordjs/discord.js/commit/ca68fc3f6b5dbe8708d065ffea5a89b23d4db757))
|
||||
|
||||
## Typings
|
||||
|
||||
- **GuildChannelManager:** Correct fetch return type (v13) (#8551) ([f4e8133](https://github.com/discordjs/discord.js/commit/f4e81330bf35bac0d8317dbb170312422df432fa))
|
||||
|
||||
# [13.10.3](https://github.com/discordjs/discord.js/compare/13.10.2...13.10.3) - (2022-08-22)
|
||||
|
||||
## Documentation
|
||||
|
||||
- Fix broken discord support link (#8485) ([11d6949](https://github.com/discordjs/discord.js/commit/11d69491e0b732bcadb54c1f39d0f6ca17d2f75f))
|
||||
|
||||
## Typings
|
||||
|
||||
- Disallow some channel types from webhook creation (#8535) ([10b12cc](https://github.com/discordjs/discord.js/commit/10b12ccea65011627649ecdfc814caffa5776e14))
|
||||
- **ModalMessageModalSubmitInteraction:** ChannelId is not nullable (v13) (#8505) ([526ea74](https://github.com/discordjs/discord.js/commit/526ea74e666556ffa13bde9130bd91388bf7a2a8))
|
||||
|
||||
# [13.10.2](https://github.com/discordjs/discord.js/compare/13.10.1...13.10.2) - (2022-08-10)
|
||||
|
||||
## Typings
|
||||
|
||||
- **Message:** Correct `bulkDelete` return type (v13) (#8469) ([03c59e3](https://github.com/discordjs/discord.js/commit/03c59e3a837edcaa428549c8387ef4d29e3ef6e4))
|
||||
|
||||
# [13.10.1](https://github.com/discordjs/discord.js/compare/13.10.0...13.10.1) - (2022-08-10)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **ThreadChannel:** Handle possibly `null` parent (v13) (#8467) ([2a46d9f](https://github.com/discordjs/discord.js/commit/2a46d9f58e4714c8580218a3459992bbfec2bcf7))
|
||||
|
||||
# [13.10.0](https://github.com/discordjs/discord.js/compare/13.9.2...13.10.0) - (2022-08-10)
|
||||
|
||||
## Features
|
||||
|
||||
- **Guild:** Add `max_video_channel_users` (v13) (#8424) ([ae43bca](https://github.com/discordjs/discord.js/commit/ae43bca8b0afd8b90db7a1d99f67205b29338c2d))
|
||||
|
||||
# [13.9.2](https://github.com/discordjs/discord.js/compare/13.9.1...13.9.2) - (2022-07-29)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **MessageMentions:** `ignoreRepliedUser` option in `has()` (v13) (#8365) ([d0a4199](https://github.com/discordjs/discord.js/commit/d0a4199760b4c7fe64f558d8d4d2302873f78b0e))
|
||||
- **GuildChannelManager:** Allow unsetting rtcRegion (v13) (#8362) ([9612507](https://github.com/discordjs/discord.js/commit/96125079a23c87fe0fb3ee01a0de5a9889fc1057))
|
||||
- **ThreadChannel:** Omit webhook fetching (v13) (#8352) ([4f7c1e3](https://github.com/discordjs/discord.js/commit/4f7c1e35c38bb9f1d524406c008ffceb2cfde3db))
|
||||
|
||||
# [13.9.1](https://github.com/discordjs/discord.js/compare/13.9.0...13.9.1) - (2022-07-23)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **ApplicationCommandManager:** Allow passing 0n to defaultMemberPermissions (v13) (#8312) ([4cf0555](https://github.com/discordjs/discord.js/commit/4cf05559a2cc6c4dfc409f8aab60256e5b030bca))
|
||||
|
||||
## Refactor
|
||||
|
||||
- **embed:** Deprecate addField (#8318) ([be35db2](https://github.com/discordjs/discord.js/commit/be35db2410c24fcca8b28ddfb3c1c580e7e2a22f))
|
||||
- **Presence:** Remove redundant date parsing (v13) (#8341) ([e95caa7](https://github.com/discordjs/discord.js/commit/e95caa7e4515beab627b5394d011a6b6a8ae6a18))
|
||||
|
||||
# [13.9.0](https://github.com/discordjs/discord.js/compare/13.8.1...13.9.0) - (2022-07-17)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **PermissionOverwriteManager:** Mutates user (#8282) ([4d86cf4](https://github.com/discordjs/discord.js/commit/4d86cf4ce0f56c4025533ef978417a5a71bd1b5c))
|
||||
- **GuildChannelManager:** Access `resolveId` correctly (v13) (#8297) ([beb3d8e](https://github.com/discordjs/discord.js/commit/beb3d8ec26d2dd8545b4d32a10a8bfcc4b0bc4bb))
|
||||
- **GuildChannelManager:** Edit lockPermissions (#8267) ([8fe166d](https://github.com/discordjs/discord.js/commit/8fe166dcfddaec0255872fa1d3f333399c8852e9))
|
||||
- **applicationcommandmanager:** Explicitly allow passing builders to methods (v13) (#8229) ([f457cdd](https://github.com/discordjs/discord.js/commit/f457cdd2dea53614e3547dca7cff99d2492455b5))
|
||||
- Pass in the expected query object type for application commands (#8189) ([f704b26](https://github.com/discordjs/discord.js/commit/f704b261c03fe45f100e30637c86338583f3510f))
|
||||
- Use non-global flag whilst resolving regular expressions (#8178) ([4063b90](https://github.com/discordjs/discord.js/commit/4063b90cefeba052168315b5899cbe69d11206c3))
|
||||
- **GuildStickerManager.fetchUser:** Changed guildId to guild.id (#8176) ([0e0f784](https://github.com/discordjs/discord.js/commit/0e0f784447e6915cb067a06d1f2589ac839d05f7))
|
||||
- **guildmemberremove:** Remove member's presence for v13 (#8182) ([e8d72c7](https://github.com/discordjs/discord.js/commit/e8d72c7245f61f730b09b0dfed71f270d87f2019))
|
||||
- **WebSocketShard:** Backport error handler preservation on connections (#8164) ([c198e89](https://github.com/discordjs/discord.js/commit/c198e893c9b8904c2877599473472bcf0a3eb158))
|
||||
|
||||
## Documentation
|
||||
|
||||
- Add new HTTP Error Codes `50068` (v13) (#8273) ([00a7057](https://github.com/discordjs/discord.js/commit/00a705707ea5494a31e245bf010b14607dc1174f))
|
||||
- Add `MessageActivityType` (v13) (#8257) ([9cc336c](https://github.com/discordjs/discord.js/commit/9cc336c43b0a618bdd74bb4cb7ccde674d43e263))
|
||||
- **MessageInteraction:** Update `commandName` description (v13) (#8220) ([feb8e30](https://github.com/discordjs/discord.js/commit/feb8e30d2e8dc5d55961416812dac1f4232eeab0))
|
||||
- **constants:** Document missing constants (#8168) ([4ae08ad](https://github.com/discordjs/discord.js/commit/4ae08ad9efd49eaf6cbb6d88bc278aecf435b4a1))
|
||||
|
||||
## Features
|
||||
|
||||
- **ApplicationCommand:** Add `min_length` and `max_length` for string option (v13) (#8217) ([a93f4b1](https://github.com/discordjs/discord.js/commit/a93f4b1ba2a08df5b5319776fe97ff9eb64476d6))
|
||||
- **interaction:** Add `appPermissions` (v13) (#8195) ([222fc9c](https://github.com/discordjs/discord.js/commit/222fc9c6792272be7a123e790f6eb13fcabdba86))
|
||||
- Partially backport perms v2 for v13 (#8162) ([125696f](https://github.com/discordjs/discord.js/commit/125696fc79df4b4d6d670acf3203955e1c300d3f))
|
||||
|
||||
## Typings
|
||||
|
||||
- **GuildMemberManager:** Non-void return of `edit()` (v13) (#8187) ([631abee](https://github.com/discordjs/discord.js/commit/631abee69310d59eb4625501cde1c44f6c44a7af))
|
||||
- Add missing shard types (v13) (#8192) ([079973f](https://github.com/discordjs/discord.js/commit/079973f1cfbbbcab9e4708ba82d0034398703ec7))
|
||||
|
||||
# [13.8.1](https://github.com/discordjs/discord.js/compare/13.8.0...13.8.1) - (2022-06-23)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **VoiceChannel:** NSFW property (v13) (#8161) ([c61fc80](https://github.com/discordjs/discord.js/commit/c61fc8082a11659bb0af29058aa7d840196295f0))
|
||||
- **ModalSubmitInteraction:** Add `isFromMessage()` missing method (#8092) ([0ab2227](https://github.com/discordjs/discord.js/commit/0ab22279847340ca84f07eab0ef86176a8f3cf0e))
|
||||
- Destroy options during cleanup (#8082) ([afb18b9](https://github.com/discordjs/discord.js/commit/afb18b99b705d29720713985994de85478d33be1))
|
||||
- **AuditLog:** Default changes to empty array (#8076) ([3095f35](https://github.com/discordjs/discord.js/commit/3095f350e0f18f4812bb27350e01325dd5dfedbf))
|
||||
|
||||
## Documentation
|
||||
|
||||
- `TextBasedChannel`-> `TextBasedChannels` typos (v13) (#8155) ([65444f5](https://github.com/discordjs/discord.js/commit/65444f510d33b856af2af549676bee406c1fef29))
|
||||
|
||||
## Refactor
|
||||
|
||||
- Deprecate `$` prefix from `ws.properties` keys (#8095) ([3638b40](https://github.com/discordjs/discord.js/commit/3638b4021ae3da8410c5626815b7d24f75160bcb))
|
||||
|
||||
## Typings
|
||||
|
||||
- **Shard#reconnecting:** Backport to v13 - Fix event name (#8126) ([70450f6](https://github.com/discordjs/discord.js/commit/70450f6873bda4b41d7bd212990c8823b93b9db6))
|
||||
- **AutocompleteOption:** Backport fix and improve types (#8078) ([613fd43](https://github.com/discordjs/discord.js/commit/613fd43fcf03d4f89ebc86f19e53bcbe624ad882))
|
||||
- **GuildChannel:** Fix type of `.isText()` method (#8061) ([0d0190a](https://github.com/discordjs/discord.js/commit/0d0190a6fdb1b4569f35b9814bae98a3556fb29a))
|
||||
|
||||
# [13.8.0](https://github.com/discordjs/discord.js/compare/13.7.0...13.8.0) - (2022-06-05)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **guildchannelmanager:** Wrong parameter in \_sortedChannels call (#8011) ([876816a](https://github.com/discordjs/discord.js/commit/876816ab2a0fd890d5bcedb3d73094c37c6b4e31))
|
||||
- **websocketshard:** Deal with zombie connection caused by 4009 (#7581) ([114bcc0](https://github.com/discordjs/discord.js/commit/114bcc07a980325a9c3a04eb35ce1284b23eaefb))
|
||||
- Video quality mode data property (#7946) ([76df9fd](https://github.com/discordjs/discord.js/commit/76df9fdc451148392a7cfac83de67b8af2fe7bb6))
|
||||
- **ApplicationCommandOptionType:** Add attachment to jsdoc (#7952) ([a51420f](https://github.com/discordjs/discord.js/commit/a51420f7f851c671b8e896d987a26172749376f5))
|
||||
|
||||
## Features
|
||||
|
||||
- Backport text-in-voice support to v13 (#7999) ([ddfe15b](https://github.com/discordjs/discord.js/commit/ddfe15b8723ad66ab48dcd7967c89c7484b71929))
|
||||
|
||||
# [13.7.0](https://github.com/discordjs/discord.js/compare/13.6.0...13.7.0) - (2022-05-13)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **MessageEmbed:** Fix a typo (#7906) ([ea28638](https://github.com/discordjs/discord.js/commit/ea28638a0c7cebb40aab36c01ed29fed02935540))
|
||||
- **GuildEditData:** Some fields can be null for v13 (#7633) ([816936e](https://github.com/discordjs/discord.js/commit/816936eafbe4b8caee10a15709a771919754f5ad))
|
||||
- Apply v14 fix (#7756) ([ab6c2ba](https://github.com/discordjs/discord.js/commit/ab6c2bad845d44b5d822b131e5e458a3637431c6))
|
||||
- **GuildChannelManager:** `delete` method accessing wrong id (#7771) ([c9e4562](https://github.com/discordjs/discord.js/commit/c9e4562fd58999452829501a3410da2b1709342f))
|
||||
- **GuildScheduledEvent:** Handle missing `image` for v13 (#7627) ([dfea9c2](https://github.com/discordjs/discord.js/commit/dfea9c27cef4ec7472c39675c93de985b43fee87))
|
||||
- **messagementions:** Fix `has` method for v13 (#7591) ([7a52785](https://github.com/discordjs/discord.js/commit/7a52785f7d3a0d2211b2ceff68f7152161a0b1f5))
|
||||
- Check if member has admininistrator on `moderatable` (v13) (#7578) ([13dd82d](https://github.com/discordjs/discord.js/commit/13dd82d7fa6bc5906103cf8c1f4bb7de5d3e8270))
|
||||
- **ThreadChannel:** Require `sendable` for `unarchivable` (#7555) ([49397c0](https://github.com/discordjs/discord.js/commit/49397c0ca4ec468a2046167afa64b7a82aa5e7fa))
|
||||
- Backport `MessageReaction#me` being incorrectly `false` (#7553) ([5f621c1](https://github.com/discordjs/discord.js/commit/5f621c19959e892066b23f06f0b6485b6cecdb4c))
|
||||
- **typings:** SweepStageInstances typo (#7521) ([f096069](https://github.com/discordjs/discord.js/commit/f0960698d2ef51d4586f3c89d8b7c94faf5d921b))
|
||||
- **MessagePayload:** V13 don't set reply flags to target flags (#7515) ([30baff7](https://github.com/discordjs/discord.js/commit/30baff7ecbe5fdb5bea9ed5b14a28a76922d507c))
|
||||
- **Shard:** V13 EventEmitter listener warning (#7479) ([77b8e01](https://github.com/discordjs/discord.js/commit/77b8e0191123b0e76832c642454adceab9b8ad13))
|
||||
- **MessageEmbed:** Set footer to undefined (#7358) ([bc5ddc3](https://github.com/discordjs/discord.js/commit/bc5ddc36fa2e1935ffc8e871c333f6613a5f2396))
|
||||
|
||||
## Documentation
|
||||
|
||||
- **shardingmanager:** Fix type of `execArgv` option (v13) (#7863) ([43a7870](https://github.com/discordjs/discord.js/commit/43a7870b2337ebdc362640a799fe5e81cfbaf739))
|
||||
- Fix and improve localization docs (v13 backport) (#7807) ([6dcf0bd](https://github.com/discordjs/discord.js/commit/6dcf0bda05ee79baa173dce02a4f8985f6f654df))
|
||||
- **ApplicationCommand:** Fix ApplicationCommandOptionChoice (#7798) ([1040ce0](https://github.com/discordjs/discord.js/commit/1040ce0e710e0e805ad75302b9078a0230309ae8))
|
||||
- Backport version 13 fixes (#7552) ([69ba067](https://github.com/discordjs/discord.js/commit/69ba067a6512fffd2be99ad0b5db2cbfcbb19c88))
|
||||
|
||||
## Features
|
||||
|
||||
- Backport (#7776) ([5165b18](https://github.com/discordjs/discord.js/commit/5165b18b85379411645ca377389b09a911fd3fc8))
|
||||
- Backport (#7787) ([3eb45e3](https://github.com/discordjs/discord.js/commit/3eb45e30b3a3b1b5624d36698b7f1af6bff3cb6d))
|
||||
- Backport (#7786) ([ab324ea](https://github.com/discordjs/discord.js/commit/ab324ea6ae042e8312e28dee1665729e6db29193))
|
||||
- Add support for localized slash commands (v13 backport) (#7766) ([022e138](https://github.com/discordjs/discord.js/commit/022e138b9a5a9038e61b5bdabade7606c9341982))
|
||||
- App authorization links and tags for v13 (#7731) ([9e4a900](https://github.com/discordjs/discord.js/commit/9e4a900e6d540ad611675ec54ba35e2b9da984dd))
|
||||
- Backport (#7777) ([6c56132](https://github.com/discordjs/discord.js/commit/6c5613255ade937384525b17f2179f4086a501f1))
|
||||
- Backport (#7778) ([ff49b82](https://github.com/discordjs/discord.js/commit/ff49b82db773f0407ac0e890897156fb52843b11))
|
||||
- Backport (#7779) ([ae7f991](https://github.com/discordjs/discord.js/commit/ae7f991e8d08222483a1e92d6740fedadc479bd5))
|
||||
- Backport (#7783) ([cedc333](https://github.com/discordjs/discord.js/commit/cedc3339401349dfa00990be204b203ef46a3545))
|
||||
- **VoiceChannel:** Support `video_quality_mode` (v13) (#7785) ([6daee1b](https://github.com/discordjs/discord.js/commit/6daee1b235fc29eb09d9dd97cbbea619225ee2e1))
|
||||
- **StageInstance:** Add support for associated guild event (#7713) ([68498a8](https://github.com/discordjs/discord.js/commit/68498a87be9436be95456768f50db638c06a6ca8))
|
||||
- **modals:** Modals, input text components and modal submits, v13 style (#7431) ([e1cdcfa](https://github.com/discordjs/discord.js/commit/e1cdcfa9a6baed1d373cc5474630d32ce38db31e))
|
||||
- Backport `Interaction#isRepliable` (#7563) ([5e8162a](https://github.com/discordjs/discord.js/commit/5e8162a1379cb3b8c02cc5b29e70911eb1389218))
|
||||
- Add methods to managers for v13 (#7611) ([9f09702](https://github.com/discordjs/discord.js/commit/9f09702854d21fd11ab3f4e2f0eec445f294130e))
|
||||
- Add `premiumSubscriptionCount` to `InviteGuild` (#7629) ([8e7d15e](https://github.com/discordjs/discord.js/commit/8e7d15e49d0b75687d4ae813d8274b7086959004))
|
||||
- **scheduledevents:** Event cover images for v13 (#7613) ([a7535a2](https://github.com/discordjs/discord.js/commit/a7535a2232c4de4553d0d2a2cee315124e1bdfaa))
|
||||
- Backport `MessageMentions` channel type fixes (#7562) ([93cdb2f](https://github.com/discordjs/discord.js/commit/93cdb2f2fa3ebde8f06cefe9de4a351b99f3b5e6))
|
||||
- Backport cache types resolving to `never` (#7561) ([611d3a7](https://github.com/discordjs/discord.js/commit/611d3a7b2f76c8be2655d8f27ec4667e6c2054cf))
|
||||
- Backport sending message flags (#7560) ([29d42ed](https://github.com/discordjs/discord.js/commit/29d42ed31959a0b5e518b46e45029b99cb15aa59))
|
||||
- **ThreadChannel:** Backport creation timestamp (#7559) ([1d97dcf](https://github.com/discordjs/discord.js/commit/1d97dcff087b75e36d8d4b20e79ec3b820868024))
|
||||
- Add custom image support to version 13 (#7557) ([679b87c](https://github.com/discordjs/discord.js/commit/679b87c4f88a7bd56bf81a9ade0fc2bf7e54495a))
|
||||
- Backport `reason` on `pin` and `unpin` (#7556) ([b231bec](https://github.com/discordjs/discord.js/commit/b231bece0e0a1600bd4e2337a2ec83c9a8df11fd))
|
||||
- **GuildPreview:** Add stickers to version 13 (#7554) ([215dfe0](https://github.com/discordjs/discord.js/commit/215dfe02d5482fcabccbc2373386eae15bdd866a))
|
||||
- Backport `sweepStickers` method (#7558) ([ee1698d](https://github.com/discordjs/discord.js/commit/ee1698d92869280dcfdbfb353712ef97dff90b56))
|
||||
- **scheduledevents:** Add image option (v13) (#7549) ([2fcf8af](https://github.com/discordjs/discord.js/commit/2fcf8af421b34b4908bb01b59cf748a1376e5535))
|
||||
- **thread:** V13 add `newlyCreated` to `threadCreate` event (#7481) ([2b3db73](https://github.com/discordjs/discord.js/commit/2b3db734dfd0e9a3cbfdd45fd3aa490b82ddaa08))
|
||||
- **commands:** Attachment options (#7441) ([5bcca8b](https://github.com/discordjs/discord.js/commit/5bcca8b97fc09d9f3149325e2b8d8bccdd61e354))
|
||||
|
||||
## Refactor
|
||||
|
||||
- Deprecate v13 properties and methods (#7782) ([b9802f4](https://github.com/discordjs/discord.js/commit/b9802f4b6f25da62a0bff049ccc165cce8c9d856))
|
||||
- Remove non-breaking stuff (#7636) ([b9c5676](https://github.com/discordjs/discord.js/commit/b9c5676006a702f704e970b3027829663b9b0a65))
|
||||
|
||||
## Typings
|
||||
|
||||
- Fix ModalSubmitInteraction (#7768) ([1d09ad4](https://github.com/discordjs/discord.js/commit/1d09ad4652796ecf39a3146631120d5600f36b6a))
|
||||
- **threadchannel:** Fix autoArchiveDuration types (#7817) ([7afcd95](https://github.com/discordjs/discord.js/commit/7afcd9594a5706526be20cb26f0de388b094c1b4))
|
||||
- **InteractionCollector:** Fix guild and channel types (#7624) ([7814074](https://github.com/discordjs/discord.js/commit/78140748ce4a64977426a93fd72c9e2783e5919d))
|
||||
- V13 channel create overloads fix (#7480) ([0b54089](https://github.com/discordjs/discord.js/commit/0b54089c43b60a325e02b78dd0126771ac71f746))
|
||||
|
||||
# [13.6.0](https://github.com/discordjs/discord.js/compare/13.5.1...13.6.0) - (2022-01-13)
|
||||
|
||||
## Documentation
|
||||
|
||||
- **interaction:** Add locale list link (#7261) ([1f4e633](https://github.com/discordjs/discord.js/commit/1f4e633ce3bd0a2398e49d3a9f6eb5ddd5e09ab9))
|
||||
|
||||
## Features
|
||||
|
||||
- Add Locales to Interactions (#7131) ([233084a](https://github.com/discordjs/discord.js/commit/233084a6018e77b7f9d94446683eef38790ed277))
|
||||
|
||||
# [13.5.1](https://github.com/discordjs/discord.js/compare/13.4.0...13.5.1) - (2022-01-07)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **sweepers:** Provide default for object param (#7182) ([2dabd82](https://github.com/discordjs/discord.js/commit/2dabd82e26134b5050f694f3a9f6524cd3d0c75c))
|
||||
- **GuildMemberManager:** Nick endpoint (#7151) ([d0c3961](https://github.com/discordjs/discord.js/commit/d0c3961aef41f17773fb14d06213df3fcb7fc8d2))
|
||||
- **Permissions:** ToArray shouldn't check admin (#7144) ([fc4292e](https://github.com/discordjs/discord.js/commit/fc4292e2e9ad381eb0ed07ef5e80a4251a5c4e9d))
|
||||
- Remove deprecation warning on `Message#cleanContent` (#7143) ([7e5f16b](https://github.com/discordjs/discord.js/commit/7e5f16b6b3060820446a325f4eb06dd60faee5a9))
|
||||
|
||||
## Documentation
|
||||
|
||||
- **Sweepers:** Fix typo (#7165) ([780b7ed](https://github.com/discordjs/discord.js/commit/780b7ed39f173a77fd9eae396133980826926906))
|
||||
|
||||
## Features
|
||||
|
||||
- **GuildMember:** Add method to check timeout (#7146) ([baacd6b](https://github.com/discordjs/discord.js/commit/baacd6ba6979f11e1af38804df15468c29ec09e3))
|
||||
@@ -192,7 +472,7 @@ All notable changes to this project will be documented in this file.
|
||||
- **GuildManager:** Remove redundant check (#6859) ([579569a](https://github.com/discordjs/discord.js/commit/579569ae18d5a2dbcb39ad5e5adfe486315467ea))
|
||||
- Remove redundant user agent parsing (#6820) ([460df9e](https://github.com/discordjs/discord.js/commit/460df9eb4df78b502a1cbbbde65dbdfd3c46f5af))
|
||||
- Remove unnecessary checks (#6777) ([e24209a](https://github.com/discordjs/discord.js/commit/e24209a8b1f02d64eb2fb2a510be7a0ad24d16a8))
|
||||
- **Role:** Move initialization of delete prop out of _patch (#6776) ([872e7a5](https://github.com/discordjs/discord.js/commit/872e7a59b2c1b891c4d1c426a4a449a1b9353500))
|
||||
- **Role:** Move initialization of delete prop out of \_patch (#6776) ([872e7a5](https://github.com/discordjs/discord.js/commit/872e7a59b2c1b891c4d1c426a4a449a1b9353500))
|
||||
|
||||
## Typings
|
||||
|
||||
@@ -218,7 +498,7 @@ All notable changes to this project will be documented in this file.
|
||||
- **AllowedImageSizes:** Add new image sizes (#6754) ([d0025be](https://github.com/discordjs/discord.js/commit/d0025beb7b1ee6611f4315be91b38788c428f1c1))
|
||||
- **User:** Compare flags in #equals (#6750) ([00e1e26](https://github.com/discordjs/discord.js/commit/00e1e2673b86e0041f2bebab7b3ced5722f450bb))
|
||||
- **VoiceState:** Patch streaming value (#6747) ([7eec061](https://github.com/discordjs/discord.js/commit/7eec06145a141d167afc7814f3cfd9e06eb292e6))
|
||||
- **Message:** Avoid overwriting properties in _patch (#6738) ([a8c21cd](https://github.com/discordjs/discord.js/commit/a8c21cd754d634b4d40047f85264528681a61b41))
|
||||
- **Message:** Avoid overwriting properties in \_patch (#6738) ([a8c21cd](https://github.com/discordjs/discord.js/commit/a8c21cd754d634b4d40047f85264528681a61b41))
|
||||
- **ReactionCollector:** Only call the filter function once (#6734) ([d15dd5f](https://github.com/discordjs/discord.js/commit/d15dd5f07dab00e8a31f0a37b1e60ea4017871d0))
|
||||
- **Shard:** Use provided timeout when respawning (#6735) ([905d100](https://github.com/discordjs/discord.js/commit/905d100d4def974223a128c6276d4a5833c04955))
|
||||
- **Role:** ToJSON() throwing due to permission bigints (#6724) ([9e421f6](https://github.com/discordjs/discord.js/commit/9e421f6ccf09230769740e069590fb8937f766b9))
|
||||
@@ -230,7 +510,7 @@ All notable changes to this project will be documented in this file.
|
||||
- **CachedManager:** Return updated data when cache is false (#6685) ([8426770](https://github.com/discordjs/discord.js/commit/84267708659e3e9bb2f8eb3b08d8923f235e8953))
|
||||
- **GuildEmoji:** Cache restricted roles and author data (#6675) ([60b8ba6](https://github.com/discordjs/discord.js/commit/60b8ba6b865ba02428d7926998af72cdaa17ea5d))
|
||||
- **Constants:** Allow undefined size (#6686) ([d3da833](https://github.com/discordjs/discord.js/commit/d3da83368def207585bce9ea95564d79b5097a55))
|
||||
- ***RoleManager:** Create set of role ids correctly (#6674) ([f8aa4bd](https://github.com/discordjs/discord.js/commit/f8aa4bd4705ee3bf7892670b944516d01146580f))
|
||||
- **\*RoleManager:** Create set of role ids correctly (#6674) ([f8aa4bd](https://github.com/discordjs/discord.js/commit/f8aa4bd4705ee3bf7892670b944516d01146580f))
|
||||
- **Shard:** Eval promise never resolves (#6649) ([5070d23](https://github.com/discordjs/discord.js/commit/5070d23914c13814a98cf8ea560853a82b226f94))
|
||||
- **xxxable:** Follow more properly with discord behavior (#6551) ([5d87398](https://github.com/discordjs/discord.js/commit/5d87398f9fc57915d5447842b4788f0c80642de0))
|
||||
- Allow null to be passed in order to reset icon/avatar (#6646) ([6033506](https://github.com/discordjs/discord.js/commit/603350645d0fe9d96b763d169215d15b3f4f71b1))
|
||||
@@ -243,7 +523,7 @@ All notable changes to this project will be documented in this file.
|
||||
- **UserUpdateAction:** Rely on client.user when ids match (#6511) ([1418649](https://github.com/discordjs/discord.js/commit/141864917ac920a081df6f6b34c13ba83e660bbf))
|
||||
- **Util:** Allow empty strings in splitMessage (#6437) ([d6e6244](https://github.com/discordjs/discord.js/commit/d6e6244336ccdcdac9a06ab453debe76b13c9bde))
|
||||
- **BaseClient:** Remove selfbot ability (#6429) ([9a833b1](https://github.com/discordjs/discord.js/commit/9a833b1e0eb638c60c4abbb9255ed64a170e4679))
|
||||
- **Sticker:** Rename method correctly to _add (#6421) ([2c449b6](https://github.com/discordjs/discord.js/commit/2c449b6b48f5cbc88e666afa852055b873994ca5))
|
||||
- **Sticker:** Rename method correctly to \_add (#6421) ([2c449b6](https://github.com/discordjs/discord.js/commit/2c449b6b48f5cbc88e666afa852055b873994ca5))
|
||||
- **Message:** Fix typo (#6435) ([ecb6e50](https://github.com/discordjs/discord.js/commit/ecb6e50b46e627e3217107d662dd19c64527976d))
|
||||
|
||||
## Documentation
|
||||
@@ -353,7 +633,7 @@ All notable changes to this project will be documented in this file.
|
||||
- **TextBasedChannelFields:** Add back createMessageCollector (#6616) ([1b016a3](https://github.com/discordjs/discord.js/commit/1b016a30c8f52a123c927c0ba44d985321567703))
|
||||
- Make `channelId` non-nullable on `MessageComponentInteraction` (#6600) ([8cc3885](https://github.com/discordjs/discord.js/commit/8cc3885739127ebc7023b6358ed0259ba7527250))
|
||||
- `Message#createMessageComponentCollector` use `MessageComponentInteractionOptions<T>` (#6596) ([c62823e](https://github.com/discordjs/discord.js/commit/c62823e43de50362ff0dabaf3fd53d2d39e5816b))
|
||||
- **MessagePayload:** Specify typings for `files` and `resolveFile` (#6608) ([ea36955](https://github.com/discordjs/discord.js/commit/ea3695585d59ed295cd0c8565f262ea6cc4fe098))
|
||||
- **MessagePayload:** Specify typings for `files` and `resolveFile` (#6608) ([ea36955](https://github.com/discordjs/discord.js/commit/ea3695585d59ed295cd0c8565f262ea6cc4fe098))
|
||||
- Collector filter parameter inference (#6574) ([0841956](https://github.com/discordjs/discord.js/commit/08419561edd710a6574b5e1449bf5dc1040580d5))
|
||||
- **MessageReference:** Correctly add undefined type (#6563) ([cdb0005](https://github.com/discordjs/discord.js/commit/cdb00053dec5223a929de4eea97a90c84c917408))
|
||||
- `@typedef` for `StageChannelResolvable` (#6568) ([2c219cb](https://github.com/discordjs/discord.js/commit/2c219cb982f73cda7f7db30af59200c754e75cee))
|
||||
@@ -366,7 +646,7 @@ All notable changes to this project will be documented in this file.
|
||||
- **CommandInteractionOptionResolver:** Add missing parameter (#6497) ([656b518](https://github.com/discordjs/discord.js/commit/656b51875f82a82a4429b50157a77d37be211534))
|
||||
- **ClientPresence:** Add type declarations and docs (#6450) ([6cac03a](https://github.com/discordjs/discord.js/commit/6cac03a39408ef14316a898eb81cc998921a8f0f))
|
||||
- **GuildChannel:** Added missing typing (#6454) ([f294d1e](https://github.com/discordjs/discord.js/commit/f294d1eff207ded337ccff6413824bb6ea60b4c7))
|
||||
- Message#_patch typings return type (#6433) ([81bb68d](https://github.com/discordjs/discord.js/commit/81bb68d3beb266fb0b508da959468a3a6f11c24c))
|
||||
- Message#\_patch typings return type (#6433) ([81bb68d](https://github.com/discordjs/discord.js/commit/81bb68d3beb266fb0b508da959468a3a6f11c24c))
|
||||
|
||||
# [13.1.0](https://github.com/discordjs/discord.js/compare/13.0.1...13.1.0) - (2021-08-12)
|
||||
|
||||
@@ -431,7 +711,7 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
- **Util:** Fix cleanContent parameter type (#6321) ([60ace9a](https://github.com/discordjs/discord.js/commit/60ace9a2d4cd2844a862f03f33d3be81b56f352b))
|
||||
|
||||
# [13.0.0] - (2021-08-06)
|
||||
# [13.0.0](https://github.com/discordjs/discord.js/compare/12.5.0...13.0.0) - (2021-08-06)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
@@ -505,7 +785,7 @@ All notable changes to this project will be documented in this file.
|
||||
- **GuildChannel:** Improve empty overwrite handling for permissionsLocked (#5821) ([6df3623](https://github.com/discordjs/discord.js/commit/6df36232a05e396d31461200725755745526d2ed))
|
||||
- **ApplicationCommands:** Allow managing commands for uncached guilds (#5729) ([24e5868](https://github.com/discordjs/discord.js/commit/24e586881865c187ff0a3044ac37f6e338cc51ee))
|
||||
- **ClientApplication:** Freeze flags (#5811) ([e990c35](https://github.com/discordjs/discord.js/commit/e990c35476fb6f7e1a5449493833140144e0469c))
|
||||
- ***:** Typedefs and typings for image & webhook options (#5805) ([a5a6e22](https://github.com/discordjs/discord.js/commit/a5a6e223166cf9af430da9003780e6582ea17b1c))
|
||||
- **\*:** Typedefs and typings for image & webhook options (#5805) ([a5a6e22](https://github.com/discordjs/discord.js/commit/a5a6e223166cf9af430da9003780e6582ea17b1c))
|
||||
- **TextBasedChannel:** Allow passing an APIMessage with split (#5815) ([93b0a4e](https://github.com/discordjs/discord.js/commit/93b0a4e005b5b1d371f7936238556db2e36cc982))
|
||||
- **PermissionOverwrites:** Optional allow/deny OverwriteData (#5810) ([a7ebb21](https://github.com/discordjs/discord.js/commit/a7ebb2145c380214567514906393c4ab87932e95))
|
||||
- **Typings:** Fix BitField toJSON/valueOf return types (#5806) ([935f819](https://github.com/discordjs/discord.js/commit/935f819207ac4219d37f3b99a2508e368626e6da))
|
||||
@@ -520,7 +800,7 @@ All notable changes to this project will be documented in this file.
|
||||
- **ApiMessage:** Only pass objects as options directly (#5793) ([3578159](https://github.com/discordjs/discord.js/commit/35781597d032fa7821e010e483c89f70ec51926c))
|
||||
- **BitField:** Throw an error if bit to resolve is undefined (#5565) ([0156f69](https://github.com/discordjs/discord.js/commit/0156f693e08fe2ad75133bf67c4aeb3e9c91a02d))
|
||||
- Remove remnants of awaitMessageComponentInteractions (#5783) ([ae78a33](https://github.com/discordjs/discord.js/commit/ae78a336e1d0d190ec9f525449332dc781e0b3bf))
|
||||
- ***:** Add missing imports for custom errors (#5767) ([e980948](https://github.com/discordjs/discord.js/commit/e980948de55e91e59c9e3293ac76bc645a058a53))
|
||||
- **\*:** Add missing imports for custom errors (#5767) ([e980948](https://github.com/discordjs/discord.js/commit/e980948de55e91e59c9e3293ac76bc645a058a53))
|
||||
- **ShardingManager:** Client error event cannot be emitted (#5559) ([d1c5b6f](https://github.com/discordjs/discord.js/commit/d1c5b6fe9e18b532ad69ed4bd82e1874a6dff4df))
|
||||
- Add components to MessageOption typedefs (#5768) ([657635c](https://github.com/discordjs/discord.js/commit/657635c1c09aa68211130bc3c56d6e8bb6e8e773))
|
||||
- **Interaction:** Add missing types and fix docs lists (#5762) ([1d57754](https://github.com/discordjs/discord.js/commit/1d57754d4654c5c95aa14afc13f8abe335314767))
|
||||
@@ -572,7 +852,7 @@ All notable changes to this project will be documented in this file.
|
||||
- **GuildChannel:** Regression on default channel type (#5251) ([e7c4f36](https://github.com/discordjs/discord.js/commit/e7c4f3672e7059c264ba67a94b87a655ea6e4da5))
|
||||
- **Guild/GuildChannel:** Methods reason arg usage (#5419) ([8411b9e](https://github.com/discordjs/discord.js/commit/8411b9e14211f83fddb00f622088979ee6586803))
|
||||
- **Role:** Pass Permissions class, not the bitfield (#5321) ([d744e51](https://github.com/discordjs/discord.js/commit/d744e51c1bdb4c7a26c0faeea1f2f45baaf5fd3c))
|
||||
- **WebSocketShard:** Key name in WebSocketShard#_send. (#5304) ([56d8b44](https://github.com/discordjs/discord.js/commit/56d8b445ede6c7915aec173a68905cda3d91f0ca))
|
||||
- **WebSocketShard:** Key name in WebSocketShard#\_send. (#5304) ([56d8b44](https://github.com/discordjs/discord.js/commit/56d8b445ede6c7915aec173a68905cda3d91f0ca))
|
||||
- **ApiMessage:** Remove resolve() from typings (#5241) ([a6bc39d](https://github.com/discordjs/discord.js/commit/a6bc39d3c699eec0b7851cda334335baa892c1de))
|
||||
- **GuildChannel:** Overload permissionsFor and BaseManager#resolve[id] (#5260) ([41bd6c2](https://github.com/discordjs/discord.js/commit/41bd6c2717faeeaa36514d39a4816f7cf65b4c02))
|
||||
- **GuildEmoji:** Check for cahnges to available in equals (#5201) ([f95f5dc](https://github.com/discordjs/discord.js/commit/f95f5dcd791b39c6a4d60dc8d64b0287e06ed768))
|
||||
@@ -590,7 +870,7 @@ All notable changes to this project will be documented in this file.
|
||||
- **Collector:** Throw an error if a non-function was provided as filter (#5034) ([7365f40](https://github.com/discordjs/discord.js/commit/7365f403006eeb28ab10f03cbf85416272678ef7))
|
||||
- **BaseGuildEmoji:** Typo in requiresColons (#5076) ([e272fd6](https://github.com/discordjs/discord.js/commit/e272fd6909a17941d2d3e4840e75436d98a41198))
|
||||
- **MessageReaction:** Set MessageReaction#me in patch method (#5047) ([6b322f4](https://github.com/discordjs/discord.js/commit/6b322f47a0f86115dab71c06c7879fe82ea04ec4))
|
||||
- **Voice*:** Filter out silent audio from video users (#5035) ([4fcb9eb](https://github.com/discordjs/discord.js/commit/4fcb9ebf300633022e2b9867fa06a586307ff17a))
|
||||
- **Voice\*:** Filter out silent audio from video users (#5035) ([4fcb9eb](https://github.com/discordjs/discord.js/commit/4fcb9ebf300633022e2b9867fa06a586307ff17a))
|
||||
- **GuildTemplate:** 'guild' getter (#5040) ([53529bd](https://github.com/discordjs/discord.js/commit/53529bd05deb449d5d9bbfa332470c9881d8093c))
|
||||
- **RoleManager:** Fix ID return value, change return type to collection (#4935) ([12a096b](https://github.com/discordjs/discord.js/commit/12a096b5f1c5ad518e73d1b9f50bb388928117dd))
|
||||
|
||||
@@ -601,7 +881,7 @@ All notable changes to this project will be documented in this file.
|
||||
- General cleanup and improvements (#6299) ([b4afcf8](https://github.com/discordjs/discord.js/commit/b4afcf8236b0fb4979deab0a097656292c59d50b))
|
||||
- Typo in ClientOptions (#6305) ([dd3a79e](https://github.com/discordjs/discord.js/commit/dd3a79eead4f01094c2c3003de717affc11fdc3c))
|
||||
- Grammar fix (#6294) ([90c2e07](https://github.com/discordjs/discord.js/commit/90c2e072bf0ab3562bd65e3a9e5e19f5c57fd69a))
|
||||
- **Client:** Mark _finalize as private (#6281) ([35fa3b3](https://github.com/discordjs/discord.js/commit/35fa3b3103998f93253a97ad1769212d60307b61))
|
||||
- **Client:** Mark \_finalize as private (#6281) ([35fa3b3](https://github.com/discordjs/discord.js/commit/35fa3b3103998f93253a97ad1769212d60307b61))
|
||||
- Update link of the guide to v13 changes (#6273) ([6e0ea02](https://github.com/discordjs/discord.js/commit/6e0ea020c0de580911917c4b480c3402619d4341))
|
||||
- Add missing semicolon to readme (#6270) ([2c452df](https://github.com/discordjs/discord.js/commit/2c452dffb8204868ec4d7126f1345a14edb5c141))
|
||||
- Change example in readme to slash command (#6250) ([626ff85](https://github.com/discordjs/discord.js/commit/626ff85ae7616a59c95d7338c0df9baead412ce3))
|
||||
@@ -626,10 +906,10 @@ All notable changes to this project will be documented in this file.
|
||||
- **MessageManager:** Document options param for #edit as required (#6031) ([db60e36](https://github.com/discordjs/discord.js/commit/db60e367b4a455ae0055f8d25bd8b42139784c55))
|
||||
- Add Partial typedef (#6029) ([b62d646](https://github.com/discordjs/discord.js/commit/b62d6462711cd6a8fda5cb031d052dd343a2c3c0))
|
||||
- Fix some missed MessageComponent collector methods (#6023) ([610b0b4](https://github.com/discordjs/discord.js/commit/610b0b4dd6b6e66c05c22eb852d2a752b99d07ba))
|
||||
- ***:** Wrap optional properties with union types in parentheses (#6021) ([ec06ba7](https://github.com/discordjs/discord.js/commit/ec06ba7ad04d21e61f3e734e489607a1a5ab3568))
|
||||
- **\*:** Wrap optional properties with union types in parentheses (#6021) ([ec06ba7](https://github.com/discordjs/discord.js/commit/ec06ba7ad04d21e61f3e734e489607a1a5ab3568))
|
||||
- **Collector:** Properly document endReason (#6016) ([7dd1a8d](https://github.com/discordjs/discord.js/commit/7dd1a8da08830525d292059ee3bd2c86d5f964f6))
|
||||
- **CreateInviteOptions:** Fix TargetType link (#6017) ([4adfc45](https://github.com/discordjs/discord.js/commit/4adfc45b5a3c916ae44aec5df358f0ca4254f723))
|
||||
- ***:** Add class links to isX() methods (#6007) ([fbdad6e](https://github.com/discordjs/discord.js/commit/fbdad6eac38e262a7045853174607c408cd6c59c))
|
||||
- **\*:** Add class links to isX() methods (#6007) ([fbdad6e](https://github.com/discordjs/discord.js/commit/fbdad6eac38e262a7045853174607c408cd6c59c))
|
||||
- WebSocketShard#send and TextBasedChannel#send (#5998) ([726073f](https://github.com/discordjs/discord.js/commit/726073fef7e0e7bf7d8d5e4a4546d8056719b59f))
|
||||
- **Util:** Methods removed on the base object (#5990) ([d742814](https://github.com/discordjs/discord.js/commit/d742814686fc2c8dfbdcb582541155cb8df170ac))
|
||||
- **Partials:** Add link to the guide (#5982) ([58183d4](https://github.com/discordjs/discord.js/commit/58183d425ba5c2cc87f29199e5c3e2ec5a936bd1))
|
||||
@@ -644,7 +924,7 @@ All notable changes to this project will be documented in this file.
|
||||
- **Channel:** Make the type news_thread an inline code-block (#5940) ([630432b](https://github.com/discordjs/discord.js/commit/630432b4e2f415b912754962948edf585aebf772))
|
||||
- **Thread:** Add links to discord api docs (#5919) ([5af2ef5](https://github.com/discordjs/discord.js/commit/5af2ef5fbc7ad11281f38384c360ae79efe63b39))
|
||||
- **MessageSelectMenu:** Fix options typings (#5922) ([75837a8](https://github.com/discordjs/discord.js/commit/75837a8252246b2bb71b76f5b15b8124cb40f0d8))
|
||||
- ***:** Add links to Discord's API objects & data (#5862) ([e0efcc6](https://github.com/discordjs/discord.js/commit/e0efcc6ab0e3f060e30438c0d990c9465c6134df))
|
||||
- **\*:** Add links to Discord's API objects & data (#5862) ([e0efcc6](https://github.com/discordjs/discord.js/commit/e0efcc6ab0e3f060e30438c0d990c9465c6134df))
|
||||
- Move embeds field into BaseMessageOptions (#5902) ([6cebeae](https://github.com/discordjs/discord.js/commit/6cebeae15e97e29acbdaf95bc7b17a1e346a2c34))
|
||||
- **Readme:** Remove dependencies badge (#5901) ([edf6f0c](https://github.com/discordjs/discord.js/commit/edf6f0ca7012b6b678367a1b5d716d0b85e23ba3))
|
||||
- **AnonymousGuild:** Add missing extends tag (#5896) ([3d96a33](https://github.com/discordjs/discord.js/commit/3d96a33bd006d514829648d166e86d15bf0b51c8))
|
||||
@@ -743,16 +1023,16 @@ All notable changes to this project will be documented in this file.
|
||||
- **WelcomeScreen:** Welcome screens (#5490) ([44e2ee7](https://github.com/discordjs/discord.js/commit/44e2ee7b20dbec79c993dbc1f30ddb643d943347))
|
||||
- Stage instance invite (#5856) ([2d12db0](https://github.com/discordjs/discord.js/commit/2d12db000f2a0a22a8919d7a63989a6e762ae335))
|
||||
- **Guild:** Add enum for premium_tier (#5868) ([a3cbcca](https://github.com/discordjs/discord.js/commit/a3cbcca13da1af416c219bd64a0a6e84bb87a057))
|
||||
- ***:** Use enums for consistency and speed (#5843) ([f7eeccb](https://github.com/discordjs/discord.js/commit/f7eeccba4b7015496df811f10cc2da2b0fab0630))
|
||||
- **\*:** Use enums for consistency and speed (#5843) ([f7eeccb](https://github.com/discordjs/discord.js/commit/f7eeccba4b7015496df811f10cc2da2b0fab0630))
|
||||
- **Widget:** Wrapper for widget.json (#5619) ([038ee99](https://github.com/discordjs/discord.js/commit/038ee99604cded41d4c67edf4bd6bc7969712f52))
|
||||
- Stage instances (#5749) ([918921e](https://github.com/discordjs/discord.js/commit/918921e8211fc16e9b12d2502f3168264246ea22))
|
||||
- ***:** Document and support embeds field in message create endpoint (#5792) ([99ff715](https://github.com/discordjs/discord.js/commit/99ff7151379fe03a1cfd52f252c0e6fc892d7776))
|
||||
- **\*:** Document and support embeds field in message create endpoint (#5792) ([99ff715](https://github.com/discordjs/discord.js/commit/99ff7151379fe03a1cfd52f252c0e6fc892d7776))
|
||||
- **Guild:** Add enum for mfa_level (#5797) ([ffabec3](https://github.com/discordjs/discord.js/commit/ffabec3a5e3651e5a0b8bcac83ee26bb909695fa))
|
||||
- **RequestHandler:** Emit more info when a rate limit was hit (#5801) ([18ac72e](https://github.com/discordjs/discord.js/commit/18ac72e457fa137d7f7f7bde876436ff643b4a63))
|
||||
- Add new APIErrors (#5794) ([e0ab836](https://github.com/discordjs/discord.js/commit/e0ab836b2d88caf0d9e1f9eba76ae46be9df0554))
|
||||
- **Util:** Allow array for StringOptions' char (#5566) ([fbcbb29](https://github.com/discordjs/discord.js/commit/fbcbb29884a35308a7af2169f5f9ae5658c458e8))
|
||||
- **GuildAuditLogs:** Make #target a channel for channel related logs (#5781) ([eb0291d](https://github.com/discordjs/discord.js/commit/eb0291d9a5078836183c1b63ea96461ec112f96e))
|
||||
- **Sharding*:** Contexts for broadcastEval (#5756) ([c6aeebb](https://github.com/discordjs/discord.js/commit/c6aeebb18d6b969f7c8bdb1b719883d4384dd03e))
|
||||
- **Sharding\*:** Contexts for broadcastEval (#5756) ([c6aeebb](https://github.com/discordjs/discord.js/commit/c6aeebb18d6b969f7c8bdb1b719883d4384dd03e))
|
||||
- **Voice:** Implement support for @discordjs/voice (#5402) ([7b2e12b](https://github.com/discordjs/discord.js/commit/7b2e12b102984abf61132e1057558ef7f04e6d83))
|
||||
- General component improvements (#5787) ([c4f1c75](https://github.com/discordjs/discord.js/commit/c4f1c75efa1cff1f9c775a266dccbe581305e79d))
|
||||
- **GuildChannelManager:** Add 'fetch' method (#4966) ([e798fb7](https://github.com/discordjs/discord.js/commit/e798fb720ee5ced008471fe899337f6817936770))
|
||||
@@ -765,7 +1045,9 @@ All notable changes to this project will be documented in this file.
|
||||
- **Esm:** Use `gen-esm-wrapper` instead of manually making the file (#5700) ([db0d7d4](https://github.com/discordjs/discord.js/commit/db0d7d4ea8e7b2bae4d1548e5617875b5ae0bbd4))
|
||||
- **Rest:** Show the data that is sent to Discord when an errors occurs (#5701) ([ef92339](https://github.com/discordjs/discord.js/commit/ef92339d073f82cdaa2bc69f7be8443ec16789a7))
|
||||
- **CommandInteraction:** Make options a collection (#5705) ([fdad140](https://github.com/discordjs/discord.js/commit/fdad14099779e61cb84dcd1cb2497e0e853a6144))
|
||||
- [**breaking**] ***:** Enforce strings (#4880) ([7b85a72](https://github.com/discordjs/discord.js/commit/7b85a7259f563ab14ae6c0a665a3dd43c486fde4))
|
||||
- **\*:** Enforce strings (#4880) ([7b85a72](https://github.com/discordjs/discord.js/commit/7b85a7259f563ab14ae6c0a665a3dd43c486fde4))
|
||||
- **BREAKING CHANGE:** Removes all Resolvables for only string inputs
|
||||
- **Co-authored-by:** SpaceEEC <spaceeec@yahoo.com>
|
||||
- **Message:** Allow editing files into messages (#5718) ([b212b64](https://github.com/discordjs/discord.js/commit/b212b64214ecee4f6118e78f9b90f3d3da574ecc))
|
||||
- Easier guards for channelUpdate (#5716) ([d52bcd4](https://github.com/discordjs/discord.js/commit/d52bcd46ec5985f9f18da37ba9d7d77209f58337))
|
||||
- Add support for fetching multiple guilds (#5472) ([48d6850](https://github.com/discordjs/discord.js/commit/48d6850d9a8c34f407a22b6b401f2ed74415acd0))
|
||||
@@ -813,8 +1095,8 @@ All notable changes to this project will be documented in this file.
|
||||
- Jsdelivr default file support (#5424) ([f469402](https://github.com/discordjs/discord.js/commit/f46940228e9f82db4af09ae2f2dad684db0d74ed))
|
||||
- **Client:** Add InviteGenerationOptions#additionalScopes (#5215) ([ae3c3d8](https://github.com/discordjs/discord.js/commit/ae3c3d80ee603fc46a28140107cb90c81da0afc9))
|
||||
- **ReactionCollector:** Event create (#4108) ([09d1f2f](https://github.com/discordjs/discord.js/commit/09d1f2f18f5ec536bb25156553986fee51c80d1e))
|
||||
- **ShardingManager:** Allow b-Eval/fetchClientValues on a specific shard when not all are ready (#5222) ([001676c](https://github.com/discordjs/discord.js/commit/001676c7a97f4e44c6601dd84aa0354ea94b7c25))
|
||||
- **GuildChannel:** Support conversion between text and news (#5022) ([5ac3b57](https://github.com/discordjs/discord.js/commit/5ac3b57f9bd53d1c20549a70942b023826f6f726))
|
||||
- **ShardingManager:** Allow b-Eval/fetchClientValues on a specific shard when not all are ready (#5222) ([001676c](https://github.com/discordjs/discord.js/commit/001676c7a97f4e44c6601dd84aa0354ea94b7c25))
|
||||
- **GuildChannel:** Support conversion between text and news (#5022) ([5ac3b57](https://github.com/discordjs/discord.js/commit/5ac3b57f9bd53d1c20549a70942b023826f6f726))
|
||||
- **BitField:** Move problematic bit into the error message (#5228) ([273e955](https://github.com/discordjs/discord.js/commit/273e9557be68eb1c2466f29e1c41e9b146a777c1))
|
||||
- **ClientEvents:** Add tuple labels to event arguments (#5225) ([764966e](https://github.com/discordjs/discord.js/commit/764966e398e693a5ec868bc22d722f8518656b3a))
|
||||
- **GuildMember:** #pending (#5121) ([c4c8171](https://github.com/discordjs/discord.js/commit/c4c817116f868cedb4ec20bcbf90b9b3d382621e))
|
||||
@@ -836,7 +1118,7 @@ All notable changes to this project will be documented in this file.
|
||||
- **Channels:** Fix incorrectly shared properties (#6262) ([5be471b](https://github.com/discordjs/discord.js/commit/5be471b47dd65616e6b3ee8afdc4a395ef60e1cc))
|
||||
- Added `TextBasedChannels` type (#6286) ([61db5f7](https://github.com/discordjs/discord.js/commit/61db5f7618e30c0502ceb6484a4fe861542088b7))
|
||||
- **MessageComponents:** Default setDisabled to true (#6279) ([3c7c822](https://github.com/discordjs/discord.js/commit/3c7c82292a914eb9bb9eb77c08a78f0861330687))
|
||||
- ***:** Use async functions (#6210) ([e2e4f65](https://github.com/discordjs/discord.js/commit/e2e4f6518b3be85b1e05efff108f1459cc3082df))
|
||||
- **\*:** Use async functions (#6210) ([e2e4f65](https://github.com/discordjs/discord.js/commit/e2e4f6518b3be85b1e05efff108f1459cc3082df))
|
||||
- **GuildChannel:** Use filter method for #members (#6253) ([7c54076](https://github.com/discordjs/discord.js/commit/7c540764f05cf0a7d312e468f828f427ec0f7541))
|
||||
- **VoiceState:** Change kick to disconnect (#6251) ([24931d7](https://github.com/discordjs/discord.js/commit/24931d713b947a568bb45a327bd6ba29966266b2))
|
||||
- Merge collections with keeping entries at max (#6242) ([bb5e648](https://github.com/discordjs/discord.js/commit/bb5e648f3daa4c34ad8379eb095a25d56ebfc242))
|
||||
@@ -856,7 +1138,7 @@ All notable changes to this project will be documented in this file.
|
||||
- Remove timer utilities from Client (#6113) ([5ca97c9](https://github.com/discordjs/discord.js/commit/5ca97c93515d4dfaa2b4951a020abc000115ed4d))
|
||||
- Remove typing caching (#6114) ([576eee8](https://github.com/discordjs/discord.js/commit/576eee8de26bf9e62f5487f6e25e9d5f5eaaa882))
|
||||
- **Channel:** Change channel types to UPPER_CASE (#6035) ([6301728](https://github.com/discordjs/discord.js/commit/6301728d35cfdc8b3ea62db5f73298de99a0902a))
|
||||
- **Managers:** Rename add to _add (#6060) ([9cd5e7e](https://github.com/discordjs/discord.js/commit/9cd5e7ed6104e40c038d17456abd0cc4a3778b9e))
|
||||
- **Managers:** Rename add to \_add (#6060) ([9cd5e7e](https://github.com/discordjs/discord.js/commit/9cd5e7ed6104e40c038d17456abd0cc4a3778b9e))
|
||||
- **ApplicationCommandManager:** Remove unused assignment (#6063) ([98a5b52](https://github.com/discordjs/discord.js/commit/98a5b52d8bb09ccca5c30d6ab583bc72d3f1b6ff))
|
||||
- Rename `Constants.OPCode` to `Opcode`, moved objects to enums (#6065) ([4eb3a2a](https://github.com/discordjs/discord.js/commit/4eb3a2a885efd480a953a23c5e5289912364ccd4))
|
||||
- **PresenceManager:** Have Presence extend Base and simplify add (#6056) ([ded93fe](https://github.com/discordjs/discord.js/commit/ded93feb5759ded880ab0f00ffc2ecffa8516bb9))
|
||||
@@ -872,11 +1154,16 @@ All notable changes to this project will be documented in this file.
|
||||
- **Presence:** Remove second assignment of `syncID` (#5956) ([fb8d516](https://github.com/discordjs/discord.js/commit/fb8d5166a8b2264b69bfd39e95798d984f971155))
|
||||
- **MessagePayload:** Rename APIMessage (#5921) ([b15d825](https://github.com/discordjs/discord.js/commit/b15d825bb3acdf432b94d8413a7a964ccc8734bc))
|
||||
- Removed `code` and `split` options (#5918) ([985d4d6](https://github.com/discordjs/discord.js/commit/985d4d6a438fc9123264f6a1c600f34fccc1825f))
|
||||
- **Co-authored-by:** Jan <66554238+vaporox@users.noreply.github.com>
|
||||
- **BREAKING CHANGE:** Removed `APIMessage#split`
|
||||
- **BREAKING CHANGE:** Removed `MessageEditOptions#code`
|
||||
- **BREAKING CHANGE:** Removed `BaseMessageOptions#code`
|
||||
- **BREAKING CHANGE:** Removed `BaseMessageOptions#split`
|
||||
- **Collector:** Make filter an option (#5903) ([0d0c8f0](https://github.com/discordjs/discord.js/commit/0d0c8f07f2535dd315ca95abe35e848c13d0ddf5))
|
||||
- Remove exported shortcuts to util methods (#5904) ([1816a93](https://github.com/discordjs/discord.js/commit/1816a93b1b1b2bae47e8651e76fa53699de8421d))
|
||||
- **Package:** Remove `runkitExampleFilename` (#5866) ([6cceb93](https://github.com/discordjs/discord.js/commit/6cceb936a796e044488e188b5939b81b11e69d23))
|
||||
- **awaitMessageComponentInteraction:** Use options object for lib consistency (#5852) ([9dda9b7](https://github.com/discordjs/discord.js/commit/9dda9b742f68dae6b2b260edcb1e5f627424693d))
|
||||
- ***:** Make typedefs for all options params (#5785) ([1ac9a2e](https://github.com/discordjs/discord.js/commit/1ac9a2eb5bfef6d009de7c54d3fac5e3d4a5afdc))
|
||||
- **\*:** Make typedefs for all options params (#5785) ([1ac9a2e](https://github.com/discordjs/discord.js/commit/1ac9a2eb5bfef6d009de7c54d3fac5e3d4a5afdc))
|
||||
- **GuildPreviewEmoji:** Make roles an array (#5720) ([4dbcaf7](https://github.com/discordjs/discord.js/commit/4dbcaf76c361b2e63e9deb08556da43ecde7909e))
|
||||
- **APIMessage:** Remove unused declarations (#5836) ([02693bc](https://github.com/discordjs/discord.js/commit/02693bc02f45980d8165820a103220f0027b96b7))
|
||||
- Fetch options consistency (#5824) ([7111b4c](https://github.com/discordjs/discord.js/commit/7111b4cd5f2690e7b6c6626025c2a6041bd64db2))
|
||||
@@ -887,9 +1174,9 @@ All notable changes to this project will be documented in this file.
|
||||
- Enforce single param on sending/editing methods (#5758) ([0467a90](https://github.com/discordjs/discord.js/commit/0467a9075fbba538c56e0cffdd2da11f7867516a))
|
||||
- GuildAvailable, typingStop from Constants (#4861) ([dda5ee2](https://github.com/discordjs/discord.js/commit/dda5ee2e9f0839d3e42d25114ae1b47355cdfd27))
|
||||
- **Interactions:** Move Structures import out of switch block (#5763) ([84e5b07](https://github.com/discordjs/discord.js/commit/84e5b075b4214c5432e380840c90091643af07fa))
|
||||
- Remove _roles from pseudo-managers (#5721) ([53d952a](https://github.com/discordjs/discord.js/commit/53d952a4ce049cd1b88d2ef4dc3dcdae487b8f00))
|
||||
- Remove \_roles from pseudo-managers (#5721) ([53d952a](https://github.com/discordjs/discord.js/commit/53d952a4ce049cd1b88d2ef4dc3dcdae487b8f00))
|
||||
- **Deps:** Use async-queue package (#5662) ([14c6802](https://github.com/discordjs/discord.js/commit/14c6802438c47a42ecb5daeb59442361ceb69213))
|
||||
- ***:** Return the invalid element when erroring from Array (#5314) ([eaf332f](https://github.com/discordjs/discord.js/commit/eaf332f83fd4376f1cee6d2c9f0939395e84740c))
|
||||
- **\*:** Return the invalid element when erroring from Array (#5314) ([eaf332f](https://github.com/discordjs/discord.js/commit/eaf332f83fd4376f1cee6d2c9f0939395e84740c))
|
||||
- **MessageOptions:** Move replyTo to reply#messageReference and add failIfNotExists (#5298) ([1ecda83](https://github.com/discordjs/discord.js/commit/1ecda83da7953052977e6297143b82f89adf1058))
|
||||
- **Sticker:** Rename Snowflake variable (#5575) ([af00ec8](https://github.com/discordjs/discord.js/commit/af00ec8970e77ea8a0afd21571eeeef9c554e1ec))
|
||||
- **RequestHandler:** Use x-ratelimit-reset-after when present (#5511) ([a5d41c9](https://github.com/discordjs/discord.js/commit/a5d41c9f6c4adc652f56c55da4f05da63873c9ef))
|
||||
@@ -934,12 +1221,12 @@ All notable changes to this project will be documented in this file.
|
||||
- **GuildInviteManager:** FetchInvitesOptions (#6076) ([c1eaa78](https://github.com/discordjs/discord.js/commit/c1eaa78ab7cef55f2a4dcb36d0876963d42ef1ec))
|
||||
- Fixed unreachable overloads (#6062) ([7322547](https://github.com/discordjs/discord.js/commit/7322547172e2d34bd04ef131db277801fccf7f99))
|
||||
- **ApplicationCommand:** Fix option name (#6067) ([58bbcd5](https://github.com/discordjs/discord.js/commit/58bbcd591e01894594dffba8bdafb95c99670fb1))
|
||||
- ***:** Revert incorrect unknown type changes (#6057) ([2e078e4](https://github.com/discordjs/discord.js/commit/2e078e44883c1ef5f85ef973d61a305ce2a34251))
|
||||
- **\*:** Revert incorrect unknown type changes (#6057) ([2e078e4](https://github.com/discordjs/discord.js/commit/2e078e44883c1ef5f85ef973d61a305ce2a34251))
|
||||
- **Options:** Should extend null (#6042) ([c4aa9fe](https://github.com/discordjs/discord.js/commit/c4aa9feee238db453c87cb66e054922a8302c355))
|
||||
- **Voice:** Move types to the library's definitions (#6041) ([185e376](https://github.com/discordjs/discord.js/commit/185e37602b0fabf6f06a02886128aead9239c5d9))
|
||||
- Better fullPermissions typings (#6028) ([2ab32e6](https://github.com/discordjs/discord.js/commit/2ab32e6bc62a5326daab6a7472075730830ef109))
|
||||
- **MessageOptions:** Fix components being optional (#6005) ([56b5b7e](https://github.com/discordjs/discord.js/commit/56b5b7ee820c8be36c6d7de0abedf1753cc591dd))
|
||||
- ***:** Create mention types (#6003) ([0dc5dd5](https://github.com/discordjs/discord.js/commit/0dc5dd5808af213ac4ede9f1084b522225a5c661))
|
||||
- **\*:** Create mention types (#6003) ([0dc5dd5](https://github.com/discordjs/discord.js/commit/0dc5dd5808af213ac4ede9f1084b522225a5c661))
|
||||
- **VoiceState:** Fix optional params (#5993) ([1242c54](https://github.com/discordjs/discord.js/commit/1242c5434d441f3f7e0ed4610a9a0815a70072ba))
|
||||
- **ClientUser:** Updated `setAFK` signature (#6011) ([c40b06c](https://github.com/discordjs/discord.js/commit/c40b06cac90b02f01e198e42c7a8f38de27f15c8))
|
||||
- **MessageSelectMenu:** Fix typings (#5995) ([fe6cc0c](https://github.com/discordjs/discord.js/commit/fe6cc0c15dde99caa1049d35f75b9335ace1721d))
|
||||
@@ -948,7 +1235,7 @@ All notable changes to this project will be documented in this file.
|
||||
- **MessageOptions:** Improved component typings (#5987) ([0eeb277](https://github.com/discordjs/discord.js/commit/0eeb2775a52b0db7f403afb7029d70897fe7d30a))
|
||||
- **ApplicationCommandPermissionsManager:** Fix types (#5979) ([388e05b](https://github.com/discordjs/discord.js/commit/388e05b4af95cf2581abae90c6d05d59a0cdb4d2))
|
||||
- **ThreadChannel:** Make locked and archived param optional (#5980) ([a08ce7d](https://github.com/discordjs/discord.js/commit/a08ce7dddb5f056128488392742495398f9e33b5))
|
||||
- ***:** Make hex color types compatible with ColorResolvable (#5973) ([788d58e](https://github.com/discordjs/discord.js/commit/788d58e5a32956bbcf4768f69ff320b0d7873a6a))
|
||||
- **\*:** Make hex color types compatible with ColorResolvable (#5973) ([788d58e](https://github.com/discordjs/discord.js/commit/788d58e5a32956bbcf4768f69ff320b0d7873a6a))
|
||||
- **CommandInteraction:** Readd followUp type (#5974) ([ae37d20](https://github.com/discordjs/discord.js/commit/ae37d202a53a05e8bba4d6df9016d0f0a7682c6b))
|
||||
- **ThreadManager:** Add type to ThreadManager#create options (#5969) ([3174507](https://github.com/discordjs/discord.js/commit/3174507d57d9f6011e97b4f3209f42179e050f9b))
|
||||
- **ColorResolvable:** Change `string` to `#${string}` (#5950) ([acdcb90](https://github.com/discordjs/discord.js/commit/acdcb906ae4691374f5d2bda1315a484c8674938))
|
||||
@@ -972,7 +1259,3 @@ All notable changes to this project will be documented in this file.
|
||||
- **MessageReaction:** Allow message to be partial (#5303) ([aac6275](https://github.com/discordjs/discord.js/commit/aac6275300a1511d2a30f0fc27999381fad4f7d9))
|
||||
- **RateLimitData:** Remove timeDifference property (#5208) ([80e1afb](https://github.com/discordjs/discord.js/commit/80e1afb65447e1d66429ddda36902d871920fdc3))
|
||||
- Make Client#voice non-nullable (#5148) ([40d77ba](https://github.com/discordjs/discord.js/commit/40d77bacc3dfdd5e9dd9f3ddff0751fe8470ddc8))
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
For breaking changes please reference: <https://discordjs.guide/additional-info/changes-in-v13.html>
|
||||
|
||||
0
apps/guide/.gitkeep
Normal file
0
apps/guide/.gitkeep
Normal file
0
apps/website/.gitkeep
Normal file
0
apps/website/.gitkeep
Normal file
77
cliff.toml
77
cliff.toml
@@ -1,33 +1,36 @@
|
||||
[changelog]
|
||||
header = """
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.\n
|
||||
"""
|
||||
body = """
|
||||
{% if version %}\
|
||||
# [{{ version | trim_start_matches(pat="v") }}]\
|
||||
{% if previous %}\
|
||||
{% if previous.version %}\
|
||||
(https://github.com/discordjs/discord.js/compare/{{ previous.version }}...{{ version }})\
|
||||
{% else %}
|
||||
(https://github.com/discordjs/discord.js/tree/{{ version }}\
|
||||
{% endif %}\
|
||||
{% endif %} \
|
||||
- ({{ timestamp | date(format="%Y-%m-%d") }})
|
||||
# [{{ version | trim_start_matches(pat="v") }}]\
|
||||
{% if previous %}\
|
||||
{% if previous.version %}\
|
||||
(https://github.com/discordjs/discord.js/compare/{{ previous.version }}...{{ version }})\
|
||||
{% else %}\
|
||||
(https://github.com/discordjs/discord.js/tree/{{ version }})\
|
||||
{% endif %}\
|
||||
{% endif %} \
|
||||
- ({{ timestamp | date(format="%Y-%m-%d") }})
|
||||
{% else %}\
|
||||
# [unreleased]
|
||||
# [unreleased]
|
||||
{% endif %}\
|
||||
{% for group, commits in commits | group_by(attribute="group") %}
|
||||
## {{ group | upper_first }}
|
||||
{% for commit in commits %}
|
||||
- {% if commit.breaking %}\
|
||||
[**breaking**] \
|
||||
{% endif %}\
|
||||
{% if commit.scope %}\
|
||||
**{{commit.scope}}:** \
|
||||
{% endif %}\
|
||||
{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}](https://github.com/discordjs/discord.js/commit/{{ commit.id }}))\
|
||||
{% endfor %}
|
||||
## {{ group | upper_first }}
|
||||
{% for commit in commits %}
|
||||
- {% if commit.scope %}\
|
||||
**{{commit.scope}}:** \
|
||||
{% endif %}\
|
||||
{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}](https://github.com/discordjs/discord.js/commit/{{ commit.id }}))\
|
||||
{% if commit.breaking %}\
|
||||
{% for breakingChange in commit.footers %}\
|
||||
\n{% raw %} {% endraw %}- **{{ breakingChange.token }}{{ breakingChange.separator }}** {{ breakingChange.value }}\
|
||||
{% endfor %}\
|
||||
{% endif %}\
|
||||
{% endfor %}
|
||||
{% endfor %}\n
|
||||
"""
|
||||
trim = true
|
||||
@@ -37,25 +40,25 @@ footer = ""
|
||||
conventional_commits = true
|
||||
filter_unconventional = true
|
||||
commit_parsers = [
|
||||
{ message = "^feat", group = "Features"},
|
||||
{ message = "^fix", group = "Bug Fixes"},
|
||||
{ message = "^docs", group = "Documentation"},
|
||||
{ message = "^perf", group = "Performance"},
|
||||
{ message = "^refactor", group = "Refactor"},
|
||||
{ message = "^typings", group = "Typings"},
|
||||
{ message = "^types", group = "Typings"},
|
||||
{ message = ".*deprecated", body = ".*deprecated", group = "Deprecation"},
|
||||
{ message = "^revert", skip = true},
|
||||
{ message = "^style", group = "Styling"},
|
||||
{ message = "^test", group = "Testing"},
|
||||
{ message = "^chore", skip = true},
|
||||
{ message = "^ci", skip = true},
|
||||
{ message = "^build", skip = true},
|
||||
{ body = ".*security", group = "Security"},
|
||||
{ message = "^feat", group = "Features"},
|
||||
{ message = "^fix", group = "Bug Fixes"},
|
||||
{ message = "^docs", group = "Documentation"},
|
||||
{ message = "^perf", group = "Performance"},
|
||||
{ message = "^refactor", group = "Refactor"},
|
||||
{ message = "^typings", group = "Typings"},
|
||||
{ message = "^types", group = "Typings"},
|
||||
{ message = ".*deprecated", body = ".*deprecated", group = "Deprecation"},
|
||||
{ message = "^revert", skip = true},
|
||||
{ message = "^style", group = "Styling"},
|
||||
{ message = "^test", group = "Testing"},
|
||||
{ message = "^chore", skip = true},
|
||||
{ message = "^ci", skip = true},
|
||||
{ message = "^build", skip = true},
|
||||
{ body = ".*security", group = "Security"},
|
||||
]
|
||||
filter_commits = true
|
||||
tag_pattern = "[0-9]*"
|
||||
skip_tags = "v[0-9]*|11|12"
|
||||
skip_tags = "v[0-9]*|@discordjs"
|
||||
ignore_tags = ""
|
||||
topo_order = false
|
||||
date_order = true
|
||||
sort_commits = "newest"
|
||||
|
||||
11638
package-lock.json
generated
11638
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
52
package.json
52
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "discord.js",
|
||||
"version": "14.0.0-dev",
|
||||
"version": "13.13.0",
|
||||
"description": "A powerful library for interacting with the Discord API",
|
||||
"scripts": {
|
||||
"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:test": "docgen --source src --custom docs/index.yml",
|
||||
"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",
|
||||
"types": "./typings/index.d.ts",
|
||||
@@ -50,36 +51,37 @@
|
||||
},
|
||||
"homepage": "https://discord.js.org",
|
||||
"dependencies": {
|
||||
"@discordjs/builders": "^0.11.0",
|
||||
"@discordjs/collection": "^0.4.0",
|
||||
"@sapphire/async-queue": "^1.1.9",
|
||||
"@types/node-fetch": "^2.5.12",
|
||||
"@types/ws": "^8.2.2",
|
||||
"discord-api-types": "^0.26.0",
|
||||
"@discordjs/builders": "^0.16.0",
|
||||
"@discordjs/collection": "^0.7.0",
|
||||
"@sapphire/async-queue": "^1.5.0",
|
||||
"@types/node-fetch": "^2.6.2",
|
||||
"@types/ws": "^8.5.3",
|
||||
"discord-api-types": "^0.33.5",
|
||||
"form-data": "^4.0.0",
|
||||
"node-fetch": "^2.6.1",
|
||||
"ws": "^8.4.0"
|
||||
"node-fetch": "^2.6.7",
|
||||
"ws": "^8.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^16.0.1",
|
||||
"@commitlint/config-angular": "^16.0.0",
|
||||
"@discordjs/docgen": "^0.11.0",
|
||||
"@favware/npm-deprecate": "^1.0.4",
|
||||
"@types/node": "^16.11.12",
|
||||
"@commitlint/cli": "^17.1.2",
|
||||
"@commitlint/config-angular": "^17.1.0",
|
||||
"@discordjs/docgen": "^0.11.1",
|
||||
"@favware/cliff-jumper": "^1.8.8",
|
||||
"@favware/npm-deprecate": "^1.0.5",
|
||||
"@types/node": "^16.11.45",
|
||||
"conventional-changelog-cli": "^2.2.2",
|
||||
"dtslint": "^4.2.1",
|
||||
"eslint": "^8.5.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-import": "^2.25.3",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"husky": "^7.0.4",
|
||||
"eslint": "^8.25.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"husky": "^8.0.1",
|
||||
"is-ci": "^3.0.1",
|
||||
"jest": "^27.4.5",
|
||||
"lint-staged": "^12.1.4",
|
||||
"prettier": "^2.5.1",
|
||||
"tsd": "^0.19.0",
|
||||
"jest": "^29.1.2",
|
||||
"lint-staged": "^13.0.3",
|
||||
"prettier": "^2.7.1",
|
||||
"tsd": "^0.24.1",
|
||||
"tslint": "^6.1.3",
|
||||
"typescript": "^4.5.4"
|
||||
"typescript": "^4.8.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.6.0",
|
||||
|
||||
@@ -4,9 +4,15 @@ class ActionsManager {
|
||||
constructor(client) {
|
||||
this.client = client;
|
||||
|
||||
this.register(require('./ApplicationCommandPermissionsUpdate'));
|
||||
this.register(require('./AutoModerationActionExecution'));
|
||||
this.register(require('./AutoModerationRuleCreate'));
|
||||
this.register(require('./AutoModerationRuleDelete'));
|
||||
this.register(require('./AutoModerationRuleUpdate'));
|
||||
this.register(require('./ChannelCreate'));
|
||||
this.register(require('./ChannelDelete'));
|
||||
this.register(require('./ChannelUpdate'));
|
||||
this.register(require('./GuildAuditLogEntryCreate'));
|
||||
this.register(require('./GuildBanAdd'));
|
||||
this.register(require('./GuildBanRemove'));
|
||||
this.register(require('./GuildChannelsPositionUpdate'));
|
||||
|
||||
34
src/client/actions/ApplicationCommandPermissionsUpdate.js
Normal file
34
src/client/actions/ApplicationCommandPermissionsUpdate.js
Normal file
@@ -0,0 +1,34 @@
|
||||
'use strict';
|
||||
|
||||
const Action = require('./Action');
|
||||
const { Events } = require('../../util/Constants');
|
||||
|
||||
/**
|
||||
* The data received in the {@link Client#event:applicationCommandPermissionsUpdate} event
|
||||
* @typedef {Object} ApplicationCommandPermissionsUpdateData
|
||||
* @property {Snowflake} id The id of the command or global entity that was updated
|
||||
* @property {Snowflake} guildId The id of the guild in which permissions were updated
|
||||
* @property {Snowflake} applicationId The id of the application that owns the command or entity being updated
|
||||
* @property {ApplicationCommandPermissions[]} permissions The updated permissions
|
||||
*/
|
||||
|
||||
class ApplicationCommandPermissionsUpdateAction extends Action {
|
||||
handle(data) {
|
||||
const client = this.client;
|
||||
/**
|
||||
* Emitted whenever permissions for an application command in a guild were updated.
|
||||
* <warn>This includes permission updates for other applications in addition to the logged in client,
|
||||
* check `data.applicationId` to verify which application the update is for</warn>
|
||||
* @event Client#applicationCommandPermissionsUpdate
|
||||
* @param {ApplicationCommandPermissionsUpdateData} data The updated permissions
|
||||
*/
|
||||
client.emit(Events.APPLICATION_COMMAND_PERMISSIONS_UPDATE, {
|
||||
permissions: data.permissions,
|
||||
id: data.id,
|
||||
guildId: data.guild_id,
|
||||
applicationId: data.application_id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ApplicationCommandPermissionsUpdateAction;
|
||||
26
src/client/actions/AutoModerationActionExecution.js
Normal file
26
src/client/actions/AutoModerationActionExecution.js
Normal file
@@ -0,0 +1,26 @@
|
||||
'use strict';
|
||||
|
||||
const Action = require('./Action');
|
||||
const AutoModerationActionExecution = require('../../structures/AutoModerationActionExecution');
|
||||
const { Events } = require('../../util/Constants');
|
||||
|
||||
class AutoModerationActionExecutionAction extends Action {
|
||||
handle(data) {
|
||||
const { client } = this;
|
||||
const guild = client.guilds.cache.get(data.guild_id);
|
||||
|
||||
if (guild) {
|
||||
/**
|
||||
* Emitted whenever an auto moderation rule is triggered.
|
||||
* <info>This event requires the {@link Permissions.FLAGS.MANAGE_GUILD} permission.</info>
|
||||
* @event Client#autoModerationActionExecution
|
||||
* @param {AutoModerationActionExecution} autoModerationActionExecution The data of the execution
|
||||
*/
|
||||
client.emit(Events.AUTO_MODERATION_ACTION_EXECUTION, new AutoModerationActionExecution(data, guild));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AutoModerationActionExecutionAction;
|
||||
27
src/client/actions/AutoModerationRuleCreate.js
Normal file
27
src/client/actions/AutoModerationRuleCreate.js
Normal file
@@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
const Action = require('./Action');
|
||||
const { Events } = require('../../util/Constants');
|
||||
|
||||
class AutoModerationRuleCreateAction extends Action {
|
||||
handle(data) {
|
||||
const { client } = this;
|
||||
const guild = client.guilds.cache.get(data.guild_id);
|
||||
|
||||
if (guild) {
|
||||
const autoModerationRule = guild.autoModerationRules._add(data);
|
||||
|
||||
/**
|
||||
* Emitted whenever an auto moderation rule is created.
|
||||
* <info>This event requires the {@link Permissions.FLAGS.MANAGE_GUILD} permission.</info>
|
||||
* @event Client#autoModerationRuleCreate
|
||||
* @param {AutoModerationRule} autoModerationRule The created auto moderation rule
|
||||
*/
|
||||
client.emit(Events.AUTO_MODERATION_RULE_CREATE, autoModerationRule);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AutoModerationRuleCreateAction;
|
||||
31
src/client/actions/AutoModerationRuleDelete.js
Normal file
31
src/client/actions/AutoModerationRuleDelete.js
Normal file
@@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
const Action = require('./Action');
|
||||
const { Events } = require('../../util/Constants');
|
||||
|
||||
class AutoModerationRuleDeleteAction extends Action {
|
||||
handle(data) {
|
||||
const { client } = this;
|
||||
const guild = client.guilds.cache.get(data.guild_id);
|
||||
|
||||
if (guild) {
|
||||
const autoModerationRule = guild.autoModerationRules.cache.get(data.id);
|
||||
|
||||
if (autoModerationRule) {
|
||||
guild.autoModerationRules.cache.delete(autoModerationRule.id);
|
||||
|
||||
/**
|
||||
* Emitted whenever an auto moderation rule is deleted.
|
||||
* <info>This event requires the {@link Permissions.FLAGS.MANAGE_GUILD} permission.</info>
|
||||
* @event Client#autoModerationRuleDelete
|
||||
* @param {AutoModerationRule} autoModerationRule The deleted auto moderation rule
|
||||
*/
|
||||
client.emit(Events.AUTO_MODERATION_RULE_DELETE, autoModerationRule);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AutoModerationRuleDeleteAction;
|
||||
29
src/client/actions/AutoModerationRuleUpdate.js
Normal file
29
src/client/actions/AutoModerationRuleUpdate.js
Normal file
@@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
const Action = require('./Action');
|
||||
const { Events } = require('../../util/Constants');
|
||||
|
||||
class AutoModerationRuleUpdateAction extends Action {
|
||||
handle(data) {
|
||||
const { client } = this;
|
||||
const guild = client.guilds.cache.get(data.guild_id);
|
||||
|
||||
if (guild) {
|
||||
const oldAutoModerationRule = guild.autoModerationRules.cache.get(data.id)?._clone() ?? null;
|
||||
const newAutoModerationRule = guild.autoModerationRules._add(data);
|
||||
|
||||
/**
|
||||
* Emitted whenever an auto moderation rule gets updated.
|
||||
* <info>This event requires the {@link Permissions.FLAGS.MANAGE_GUILD} permission.</info>
|
||||
* @event Client#autoModerationRuleUpdate
|
||||
* @param {?AutoModerationRule} oldAutoModerationRule The auto moderation rule before the update
|
||||
* @param {AutoModerationRule} newAutoModerationRule The auto moderation rule after the update
|
||||
*/
|
||||
client.emit(Events.AUTO_MODERATION_RULE_UPDATE, oldAutoModerationRule, newAutoModerationRule);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AutoModerationRuleUpdateAction;
|
||||
29
src/client/actions/GuildAuditLogEntryCreate.js
Normal file
29
src/client/actions/GuildAuditLogEntryCreate.js
Normal file
@@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
const Action = require('./Action');
|
||||
const GuildAuditLogsEntry = require('../../structures/GuildAuditLogs').Entry;
|
||||
const { Events } = require('../../util/Constants');
|
||||
|
||||
class GuildAuditLogEntryCreateAction extends Action {
|
||||
handle(data) {
|
||||
const client = this.client;
|
||||
const guild = client.guilds.cache.get(data.guild_id);
|
||||
let auditLogEntry;
|
||||
|
||||
if (guild) {
|
||||
auditLogEntry = new GuildAuditLogsEntry(guild, data);
|
||||
|
||||
/**
|
||||
* Emitted whenever a guild audit log entry is created.
|
||||
* @event Client#guildAuditLogEntryCreate
|
||||
* @param {GuildAuditLogsEntry} auditLogEntry The entry that was created
|
||||
* @param {Guild} guild The guild where the entry was created
|
||||
*/
|
||||
client.emit(Events.GUILD_AUDIT_LOG_ENTRY_CREATE, auditLogEntry, guild);
|
||||
}
|
||||
|
||||
return { auditLogEntry };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GuildAuditLogEntryCreateAction;
|
||||
@@ -22,6 +22,7 @@ class GuildMemberRemoveAction extends Action {
|
||||
*/
|
||||
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);
|
||||
}
|
||||
return { guild, member };
|
||||
|
||||
@@ -30,7 +30,7 @@ class GuildMemberUpdateAction extends Action {
|
||||
} else {
|
||||
const newMember = guild.members._add(data);
|
||||
/**
|
||||
* Emitted whenever a member becomes available in a large guild.
|
||||
* Emitted whenever a member becomes available.
|
||||
* @event Client#guildMemberAvailable
|
||||
* @param {GuildMember} member The member that became available
|
||||
*/
|
||||
|
||||
@@ -6,6 +6,7 @@ const AutocompleteInteraction = require('../../structures/AutocompleteInteractio
|
||||
const ButtonInteraction = require('../../structures/ButtonInteraction');
|
||||
const CommandInteraction = require('../../structures/CommandInteraction');
|
||||
const MessageContextMenuInteraction = require('../../structures/MessageContextMenuInteraction');
|
||||
const ModalSubmitInteraction = require('../../structures/ModalSubmitInteraction');
|
||||
const SelectMenuInteraction = require('../../structures/SelectMenuInteraction');
|
||||
const UserContextMenuInteraction = require('../../structures/UserContextMenuInteraction');
|
||||
const { Events, InteractionTypes, MessageComponentTypes, ApplicationCommandTypes } = require('../../util/Constants');
|
||||
@@ -17,9 +18,11 @@ class InteractionCreateAction extends Action {
|
||||
const client = this.client;
|
||||
|
||||
// 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;
|
||||
|
||||
switch (data.type) {
|
||||
case InteractionTypes.APPLICATION_COMMAND:
|
||||
switch (data.data.type) {
|
||||
@@ -30,6 +33,7 @@ class InteractionCreateAction extends Action {
|
||||
InteractionType = UserContextMenuInteraction;
|
||||
break;
|
||||
case ApplicationCommandTypes.MESSAGE:
|
||||
if (channel && !channel.isText()) return;
|
||||
InteractionType = MessageContextMenuInteraction;
|
||||
break;
|
||||
default:
|
||||
@@ -41,6 +45,8 @@ class InteractionCreateAction extends Action {
|
||||
}
|
||||
break;
|
||||
case InteractionTypes.MESSAGE_COMPONENT:
|
||||
if (channel && !channel.isText()) return;
|
||||
|
||||
switch (data.data.component_type) {
|
||||
case MessageComponentTypes.BUTTON:
|
||||
InteractionType = ButtonInteraction;
|
||||
@@ -59,6 +65,9 @@ class InteractionCreateAction extends Action {
|
||||
case InteractionTypes.APPLICATION_COMMAND_AUTOCOMPLETE:
|
||||
InteractionType = AutocompleteInteraction;
|
||||
break;
|
||||
case InteractionTypes.MODAL_SUBMIT:
|
||||
InteractionType = ModalSubmitInteraction;
|
||||
break;
|
||||
default:
|
||||
client.emit(Events.DEBUG, `[INTERACTION] Received interaction with unknown type: ${data.type}`);
|
||||
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.
|
||||
* @event Client#threadCreate
|
||||
* @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 };
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ class WebhooksUpdate extends Action {
|
||||
/**
|
||||
* Emitted whenever a channel has its webhooks changed.
|
||||
* @event Client#webhookUpdate
|
||||
* @param {TextChannel|NewsChannel} channel The channel that had a webhook update
|
||||
* @param {TextChannel|NewsChannel|VoiceChannel|ForumChannel} channel The channel that had a webhook update
|
||||
*/
|
||||
if (channel) client.emit(Events.WEBHOOKS_UPDATE, channel);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ const BeforeReadyWhitelist = [
|
||||
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 = [
|
||||
RPCErrorCodes.UnknownError,
|
||||
RPCErrorCodes.InvalidPermissions,
|
||||
@@ -31,7 +31,7 @@ const UNRESUMABLE_CLOSE_CODES = [
|
||||
* The WebSocket manager for this client.
|
||||
* <info>This class forwards raw dispatch events,
|
||||
* read more about it here {@link https://discord.com/developers/docs/topics/gateway}</info>
|
||||
* @extends EventEmitter
|
||||
* @extends {EventEmitter}
|
||||
*/
|
||||
class WebSocketManager extends EventEmitter {
|
||||
constructor(client) {
|
||||
@@ -216,13 +216,8 @@ class WebSocketManager extends EventEmitter {
|
||||
|
||||
this.shardQueue.add(shard);
|
||||
|
||||
if (shard.sessionId) {
|
||||
this.debug(`Session id is present, attempting an immediate reconnect...`, shard);
|
||||
this.reconnect();
|
||||
} else {
|
||||
shard.destroy({ reset: true, emit: false, log: false });
|
||||
this.reconnect();
|
||||
}
|
||||
if (shard.sessionId) this.debug(`Session id is present, attempting an immediate reconnect...`, shard);
|
||||
this.reconnect();
|
||||
});
|
||||
|
||||
shard.on(ShardEvents.INVALID_SESSION, () => {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
const EventEmitter = require('node:events');
|
||||
const { setTimeout, setInterval } = require('node:timers');
|
||||
const { setTimeout, setInterval, clearTimeout } = require('node:timers');
|
||||
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 STATUS_KEYS = Object.keys(Status);
|
||||
@@ -17,6 +17,7 @@ try {
|
||||
|
||||
/**
|
||||
* Represents a Shard's WebSocket connection
|
||||
* @extends {EventEmitter}
|
||||
*/
|
||||
class WebSocketShard extends EventEmitter {
|
||||
constructor(manager, id) {
|
||||
@@ -34,6 +35,13 @@ class WebSocketShard extends EventEmitter {
|
||||
*/
|
||||
this.id = id;
|
||||
|
||||
/**
|
||||
* The resume URL for this shard
|
||||
* @type {?string}
|
||||
* @private
|
||||
*/
|
||||
this.resumeURL = null;
|
||||
|
||||
/**
|
||||
* The current status of the shard
|
||||
* @type {Status}
|
||||
@@ -81,6 +89,13 @@ class WebSocketShard extends EventEmitter {
|
||||
*/
|
||||
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
|
||||
* @name WebSocketShard#ratelimit
|
||||
@@ -126,6 +141,14 @@ class WebSocketShard extends EventEmitter {
|
||||
*/
|
||||
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
|
||||
* @name WebSocketShard#eventsAttached
|
||||
@@ -175,12 +198,14 @@ class WebSocketShard extends EventEmitter {
|
||||
* or reject if we couldn't connect
|
||||
*/
|
||||
connect() {
|
||||
const { gateway, client } = this.manager;
|
||||
const { client } = this.manager;
|
||||
|
||||
if (this.connection?.readyState === WebSocket.OPEN && this.status === Status.READY) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const gateway = this.resumeURL ?? this.manager.gateway;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const cleanup = () => {
|
||||
this.removeListener(ShardEvents.CLOSE, onClose);
|
||||
@@ -250,10 +275,11 @@ class WebSocketShard extends EventEmitter {
|
||||
|
||||
this.status = this.status === Status.DISCONNECTED ? Status.RECONNECTING : Status.CONNECTING;
|
||||
this.setHelloTimeout();
|
||||
|
||||
this.setWsCloseTimeout(-1);
|
||||
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.onmessage = this.onMessage.bind(this);
|
||||
ws.onerror = this.onError.bind(this);
|
||||
@@ -340,21 +366,39 @@ class WebSocketShard extends EventEmitter {
|
||||
* @private
|
||||
*/
|
||||
onClose(event) {
|
||||
this.closeEmitted = true;
|
||||
if (this.sequence !== -1) this.closeSequence = this.sequence;
|
||||
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]
|
||||
Event Code: ${event.code}
|
||||
Clean : ${event.wasClean}
|
||||
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.
|
||||
* @private
|
||||
@@ -383,10 +427,11 @@ class WebSocketShard extends EventEmitter {
|
||||
*/
|
||||
this.emit(ShardEvents.READY);
|
||||
|
||||
this.resumeURL = packet.d.resume_gateway_url;
|
||||
this.sessionId = packet.d.session_id;
|
||||
this.expectedGuilds = new Set(packet.d.guilds.map(d => d.id));
|
||||
this.status = Status.WAITING_FOR_GUILDS;
|
||||
this.debug(`[READY] Session ${this.sessionId}.`);
|
||||
this.debug(`[READY] Session ${this.sessionId} | Resume url ${this.resumeURL}.`);
|
||||
this.lastHeartbeatAcked = true;
|
||||
this.sendHeartbeat('ReadyHeartbeat');
|
||||
break;
|
||||
@@ -432,6 +477,10 @@ class WebSocketShard extends EventEmitter {
|
||||
// Set the status to reconnecting
|
||||
this.status = Status.RECONNECTING;
|
||||
// Finally, emit the INVALID_SESSION event
|
||||
/**
|
||||
* Emitted when the session has been invalidated.
|
||||
* @event WebSocketShard#invalidSession
|
||||
*/
|
||||
this.emit(ShardEvents.INVALID_SESSION);
|
||||
break;
|
||||
case Opcodes.HEARTBEAT_ACK:
|
||||
@@ -523,6 +572,47 @@ class WebSocketShard extends EventEmitter {
|
||||
}, 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);
|
||||
|
||||
// Check if close event was emitted.
|
||||
if (this.closeEmitted) {
|
||||
this.debug(`[WebSocket] close was already emitted, assuming the connection was closed properly.`);
|
||||
// Setting the variable false to check for zombie connections.
|
||||
this.closeEmitted = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.debug(
|
||||
// eslint-disable-next-line max-len
|
||||
`[WebSocket] Close Emitted: ${this.closeEmitted} | did not close properly, assuming a zombie connection.\nEmitting close and reconnecting again.`,
|
||||
);
|
||||
|
||||
if (this.connection) this._cleanupConnection();
|
||||
|
||||
this.emitClose({
|
||||
code: 4009,
|
||||
reason: 'Session time out.',
|
||||
wasClean: false,
|
||||
});
|
||||
}, time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the heartbeat timer for this shard.
|
||||
* @param {number} time If -1, clears the interval, any other number sets an interval
|
||||
@@ -563,8 +653,7 @@ class WebSocketShard extends EventEmitter {
|
||||
Sequence : ${this.sequence}
|
||||
Connection State: ${this.connection ? CONNECTION_STATE[this.connection.readyState] : 'No Connection??'}`,
|
||||
);
|
||||
|
||||
this.destroy({ closeCode: 4009, reset: true });
|
||||
this.destroy({ reset: true, closeCode: 4009 });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -713,21 +802,30 @@ class WebSocketShard extends EventEmitter {
|
||||
this.setHeartbeatTimer(-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
|
||||
if (this.connection) {
|
||||
// If the connection is currently opened, we will (hopefully) receive close
|
||||
if (this.connection.readyState === WebSocket.OPEN) {
|
||||
this.connection.close(closeCode);
|
||||
this.debug(`[WebSocket] Close: Tried closing. | WS State: ${CONNECTION_STATE[this.connection.readyState]}`);
|
||||
} else {
|
||||
// Connection is not OPEN
|
||||
this.debug(`WS State: ${CONNECTION_STATE[this.connection.readyState]}`);
|
||||
// Remove listeners from the connection
|
||||
this._cleanupConnection();
|
||||
// Attempt to close the connection just in case
|
||||
try {
|
||||
this.connection.close(closeCode);
|
||||
} catch {
|
||||
// No-op
|
||||
} catch (err) {
|
||||
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
|
||||
if (emit) this._emitDestroyed();
|
||||
@@ -737,6 +835,12 @@ class WebSocketShard extends EventEmitter {
|
||||
this._emitDestroyed();
|
||||
}
|
||||
|
||||
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
|
||||
this.connection = null;
|
||||
|
||||
@@ -746,8 +850,9 @@ class WebSocketShard extends EventEmitter {
|
||||
// Step 4: Cache the old sequence (use to attempt a resume)
|
||||
if (this.sequence !== -1) this.closeSequence = this.sequence;
|
||||
|
||||
// Step 5: Reset the sequence and session id if requested
|
||||
// Step 5: Reset the sequence, resume URL and session id if requested
|
||||
if (reset) {
|
||||
this.resumeURL = null;
|
||||
this.sequence = -1;
|
||||
this.sessionId = null;
|
||||
}
|
||||
@@ -766,7 +871,8 @@ class WebSocketShard extends EventEmitter {
|
||||
* @private
|
||||
*/
|
||||
_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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = (client, packet) => {
|
||||
client.actions.ApplicationCommandPermissionsUpdate.handle(packet.d);
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = (client, packet) => {
|
||||
client.actions.AutoModerationActionExecution.handle(packet.d);
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = (client, packet) => {
|
||||
client.actions.AutoModerationRuleCreate.handle(packet.d);
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = (client, packet) => {
|
||||
client.actions.AutoModerationRuleDelete.handle(packet.d);
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = (client, packet) => {
|
||||
client.actions.AutoModerationRuleUpdate.handle(packet.d);
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = (client, packet) => {
|
||||
client.actions.GuildAuditLogEntryCreate.handle(packet.d);
|
||||
};
|
||||
@@ -19,6 +19,8 @@ module.exports = (client, { d: data }) => {
|
||||
* @property {number} index Index of the received chunk
|
||||
* @property {number} count Number of chunks the client should receive
|
||||
* @property {?string} nonce Nonce for this chunk
|
||||
* @property {Array<*>} notFound An array of whatever could not be found
|
||||
* when using {@link Opcodes.REQUEST_GUILD_MEMBERS}
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -32,5 +34,6 @@ module.exports = (client, { d: data }) => {
|
||||
count: data.chunk_count,
|
||||
index: data.chunk_index,
|
||||
nonce: data.nonce,
|
||||
notFound: data.not_found,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -6,6 +6,12 @@ const handlers = Object.fromEntries([
|
||||
['APPLICATION_COMMAND_CREATE', require('./APPLICATION_COMMAND_CREATE')],
|
||||
['APPLICATION_COMMAND_DELETE', require('./APPLICATION_COMMAND_DELETE')],
|
||||
['APPLICATION_COMMAND_UPDATE', require('./APPLICATION_COMMAND_UPDATE')],
|
||||
['APPLICATION_COMMAND_PERMISSIONS_UPDATE', require('./APPLICATION_COMMAND_PERMISSIONS_UPDATE')],
|
||||
['AUTO_MODERATION_ACTION_EXECUTION', require('./AUTO_MODERATION_ACTION_EXECUTION')],
|
||||
['AUTO_MODERATION_RULE_CREATE', require('./AUTO_MODERATION_RULE_CREATE')],
|
||||
['AUTO_MODERATION_RULE_DELETE', require('./AUTO_MODERATION_RULE_DELETE')],
|
||||
['AUTO_MODERATION_RULE_UPDATE', require('./AUTO_MODERATION_RULE_UPDATE')],
|
||||
['GUILD_AUDIT_LOG_ENTRY_CREATE', require('./GUILD_AUDIT_LOG_ENTRY_CREATE')],
|
||||
['GUILD_CREATE', require('./GUILD_CREATE')],
|
||||
['GUILD_DELETE', require('./GUILD_DELETE')],
|
||||
['GUILD_UPDATE', require('./GUILD_UPDATE')],
|
||||
|
||||
@@ -58,6 +58,14 @@ const Messages = {
|
||||
SELECT_OPTION_VALUE: 'MessageSelectOption value 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}`,
|
||||
|
||||
FILE_NOT_FOUND: file => `File could not be found: ${file}`,
|
||||
@@ -137,6 +145,7 @@ const Messages = {
|
||||
|
||||
INTERACTION_ALREADY_REPLIED: 'The reply to this interaction has already been sent or deferred.',
|
||||
INTERACTION_NOT_REPLIED: 'The reply to this interaction has not been sent or deferred.',
|
||||
/** @deprecated */
|
||||
INTERACTION_EPHEMERAL_REPLIED: 'Ephemeral responses cannot be deleted.',
|
||||
|
||||
COMMAND_INTERACTION_OPTION_NOT_FOUND: name => `Required option "${name}" not found.`,
|
||||
@@ -148,11 +157,17 @@ const Messages = {
|
||||
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.',
|
||||
|
||||
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',
|
||||
|
||||
NOT_IMPLEMENTED: (what, name) => `Method ${what} not implemented on ${name}.`,
|
||||
|
||||
SWEEP_FILTER_RETURN: 'The return value of the sweepFilter function was not false or a Function',
|
||||
|
||||
GUILD_FORUM_MESSAGE_REQUIRED: 'You must provide a message to create a guild forum thread',
|
||||
};
|
||||
|
||||
for (const [name, message] of Object.entries(Messages)) register(name, message);
|
||||
|
||||
@@ -18,6 +18,7 @@ exports.Constants = require('./util/Constants');
|
||||
exports.DataResolver = require('./util/DataResolver');
|
||||
exports.DiscordAPIError = require('./rest/DiscordAPIError');
|
||||
exports.Formatters = require('./util/Formatters');
|
||||
exports.GuildMemberFlags = require('./util/GuildMemberFlags');
|
||||
exports.HTTPError = require('./rest/HTTPError');
|
||||
exports.Intents = require('./util/Intents');
|
||||
exports.LimitedCollection = require('./util/LimitedCollection');
|
||||
@@ -36,6 +37,7 @@ exports.version = require('../package.json').version;
|
||||
// Managers
|
||||
exports.ApplicationCommandManager = require('./managers/ApplicationCommandManager');
|
||||
exports.ApplicationCommandPermissionsManager = require('./managers/ApplicationCommandPermissionsManager');
|
||||
exports.AutoModerationRuleManager = require('./managers/AutoModerationRuleManager');
|
||||
exports.BaseGuildEmojiManager = require('./managers/BaseGuildEmojiManager');
|
||||
exports.CachedManager = require('./managers/CachedManager');
|
||||
exports.ChannelManager = require('./managers/ChannelManager');
|
||||
@@ -71,7 +73,11 @@ exports.Activity = require('./structures/Presence').Activity;
|
||||
exports.AnonymousGuild = require('./structures/AnonymousGuild');
|
||||
exports.Application = require('./structures/interfaces/Application');
|
||||
exports.ApplicationCommand = require('./structures/ApplicationCommand');
|
||||
exports.ApplicationRoleConnectionMetadata =
|
||||
require('./structures/ApplicationRoleConnectionMetadata').ApplicationRoleConnectionMetadata;
|
||||
exports.AutocompleteInteraction = require('./structures/AutocompleteInteraction');
|
||||
exports.AutoModerationActionExecution = require('./structures/AutoModerationActionExecution');
|
||||
exports.AutoModerationRule = require('./structures/AutoModerationRule');
|
||||
exports.Base = require('./structures/Base');
|
||||
exports.BaseCommandInteraction = require('./structures/BaseCommandInteraction');
|
||||
exports.BaseGuild = require('./structures/BaseGuild');
|
||||
@@ -122,6 +128,8 @@ exports.MessageMentions = require('./structures/MessageMentions');
|
||||
exports.MessagePayload = require('./structures/MessagePayload');
|
||||
exports.MessageReaction = require('./structures/MessageReaction');
|
||||
exports.MessageSelectMenu = require('./structures/MessageSelectMenu');
|
||||
exports.Modal = require('./structures/Modal');
|
||||
exports.ModalSubmitInteraction = require('./structures/ModalSubmitInteraction');
|
||||
exports.NewsChannel = require('./structures/NewsChannel');
|
||||
exports.OAuth2Guild = require('./structures/OAuth2Guild');
|
||||
exports.PartialGroupDMChannel = require('./structures/PartialGroupDMChannel');
|
||||
@@ -140,6 +148,7 @@ exports.StoreChannel = require('./structures/StoreChannel');
|
||||
exports.Team = require('./structures/Team');
|
||||
exports.TeamMember = require('./structures/TeamMember');
|
||||
exports.TextChannel = require('./structures/TextChannel');
|
||||
exports.TextInputComponent = require('./structures/TextInputComponent');
|
||||
exports.ThreadChannel = require('./structures/ThreadChannel');
|
||||
exports.ThreadMember = require('./structures/ThreadMember');
|
||||
exports.Typing = require('./structures/Typing');
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
const { isJSONEncodable } = require('@discordjs/builders');
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const ApplicationCommandPermissionsManager = require('./ApplicationCommandPermissionsManager');
|
||||
const CachedManager = require('./CachedManager');
|
||||
const { TypeError } = require('../errors');
|
||||
const ApplicationCommand = require('../structures/ApplicationCommand');
|
||||
const { ApplicationCommandTypes } = require('../util/Constants');
|
||||
const Permissions = require('../util/Permissions');
|
||||
|
||||
/**
|
||||
* Manages API methods for application commands and stores their cache.
|
||||
@@ -53,6 +55,13 @@ class ApplicationCommandManager extends CachedManager {
|
||||
* @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
|
||||
* @typedef {Object} BaseFetchOptions
|
||||
@@ -64,6 +73,8 @@ class ApplicationCommandManager extends CachedManager {
|
||||
* Options used to fetch Application Commands from Discord
|
||||
* @typedef {BaseFetchOptions} FetchApplicationCommandOptions
|
||||
* @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`))
|
||||
* .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') {
|
||||
({ guildId, cache = true } = id);
|
||||
({ guildId, cache = true, locale, withLocalizations } = id);
|
||||
} else if (id) {
|
||||
if (!force) {
|
||||
const existing = this.cache.get(id);
|
||||
@@ -94,13 +105,18 @@ class ApplicationCommandManager extends CachedManager {
|
||||
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());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
* ignored when using a {@link GuildApplicationCommandManager}
|
||||
* @returns {Promise<ApplicationCommand>}
|
||||
@@ -122,7 +138,7 @@ class ApplicationCommandManager extends CachedManager {
|
||||
|
||||
/**
|
||||
* 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,
|
||||
* ignored when using a {@link GuildApplicationCommandManager}
|
||||
* @returns {Promise<Collection<Snowflake, ApplicationCommand>>}
|
||||
@@ -152,7 +168,7 @@ class ApplicationCommandManager extends CachedManager {
|
||||
/**
|
||||
* Edits an application command.
|
||||
* @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,
|
||||
* ignored when using a {@link GuildApplicationCommandManager}
|
||||
* @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.
|
||||
* @param {ApplicationCommandData|APIApplicationCommand} command The command to transform
|
||||
* @param {ApplicationCommandDataResolvable} command The command to transform
|
||||
* @returns {APIApplicationCommand}
|
||||
* @private
|
||||
*/
|
||||
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 {
|
||||
name: command.name,
|
||||
name_localizations: command.nameLocalizations ?? command.name_localizations,
|
||||
description: command.description,
|
||||
description_localizations: command.descriptionLocalizations ?? command.description_localizations,
|
||||
type: typeof command.type === 'number' ? command.type : ApplicationCommandTypes[command.type],
|
||||
options: command.options?.map(o => ApplicationCommand.transformOption(o)),
|
||||
default_permission: command.defaultPermission ?? command.default_permission,
|
||||
default_member_permissions,
|
||||
dm_permission: command.dmPermission ?? command.dm_permission,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
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}
|
||||
*/
|
||||
|
||||
288
src/managers/AutoModerationRuleManager.js
Normal file
288
src/managers/AutoModerationRuleManager.js
Normal file
@@ -0,0 +1,288 @@
|
||||
'use strict';
|
||||
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const CachedManager = require('./CachedManager');
|
||||
const AutoModerationRule = require('../structures/AutoModerationRule');
|
||||
const {
|
||||
AutoModerationRuleEventTypes,
|
||||
AutoModerationRuleTriggerTypes,
|
||||
AutoModerationActionTypes,
|
||||
AutoModerationRuleKeywordPresetTypes,
|
||||
} = require('../util/Constants');
|
||||
|
||||
/**
|
||||
* Manages API methods for auto moderation rules and stores their cache.
|
||||
* @extends {CachedManager}
|
||||
*/
|
||||
class AutoModerationRuleManager extends CachedManager {
|
||||
constructor(guild, iterable) {
|
||||
super(guild.client, AutoModerationRule, iterable);
|
||||
|
||||
/**
|
||||
* The guild this manager belongs to.
|
||||
* @type {Guild}
|
||||
*/
|
||||
this.guild = guild;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves an {@link AutoModerationRuleResolvable} to an {@link AutoModerationRule} object.
|
||||
* @method resolve
|
||||
* @memberof AutoModerationRuleManager
|
||||
* @instance
|
||||
* @param {AutoModerationRuleResolvable} autoModerationRule The AutoModerationRule resolvable to resolve
|
||||
* @returns {?AutoModerationRule}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resolves an {@link AutoModerationRuleResolvable} to a {@link AutoModerationRule} id.
|
||||
* @method resolveId
|
||||
* @memberof AutoModerationRuleManager
|
||||
* @instance
|
||||
* @param {AutoModerationRuleResolvable} autoModerationRule The AutoModerationRule resolvable to resolve
|
||||
* @returns {?Snowflake}
|
||||
*/
|
||||
|
||||
_add(data, cache) {
|
||||
return super._add(data, cache, { extras: [this.guild] });
|
||||
}
|
||||
|
||||
/**
|
||||
* Options used to set the trigger metadata of an auto moderation rule.
|
||||
* @typedef {Object} AutoModerationTriggerMetadataOptions
|
||||
* @property {string[]} [keywordFilter] The substrings that will be searched for in the content
|
||||
* @property {string[]} [regexPatterns] The regular expression patterns which will be matched against the content
|
||||
* <info>Only Rust-flavored regular expressions are supported.</info>
|
||||
* @property {AutoModerationRuleKeywordPresetType[]} [presets]
|
||||
* The internally pre-defined wordsets which will be searched for in the content
|
||||
* @property {string[]} [allowList] The substrings that will be exempt from triggering
|
||||
* {@link AutoModerationRuleTriggerType.KEYWORD} and {@link AutoModerationRuleTriggerType.KEYWORD_PRESET}
|
||||
* @property {?number} [mentionTotalLimit] The total number of role & user mentions allowed per message
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options used to set the actions of an auto moderation rule.
|
||||
* @typedef {Object} AutoModerationActionOptions
|
||||
* @property {AutoModerationActionType} type The type of this auto moderation rule action
|
||||
* @property {AutoModerationActionMetadataOptions} [metadata] Additional metadata needed during execution
|
||||
* <info>This property is required if using a `type` of
|
||||
* {@link AutoModerationActionType.SEND_ALERT_MESSAGE} or {@link AutoModerationActionType.TIMEOUT}.</info>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options used to set the metadata of an auto moderation rule action.
|
||||
* @typedef {Object} AutoModerationActionMetadataOptions
|
||||
* @property {GuildTextChannelResolvable|ThreadChannel} [channel] The channel to which content will be logged
|
||||
* @property {number} [durationSeconds] The timeout duration in seconds
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options used to create an auto moderation rule.
|
||||
* @typedef {Object} AutoModerationRuleCreateOptions
|
||||
* @property {string} name The name of the auto moderation rule
|
||||
* @property {AutoModerationRuleEventType} eventType The event type of the auto moderation rule
|
||||
* @property {AutoModerationRuleTriggerType} triggerType The trigger type of the auto moderation rule
|
||||
* @property {AutoModerationTriggerMetadataOptions} [triggerMetadata] The trigger metadata of the auto moderation rule
|
||||
* <info>This property is required if using a `triggerType` of
|
||||
* {@link AutoModerationRuleTriggerTypes.KEYWORD}, {@link AutoModerationRuleTriggerTypes.KEYWORD_PRESET},
|
||||
* or {@link AutoModerationRuleTriggerTypes.MENTION_SPAM}.</info>
|
||||
* @property {AutoModerationActionOptions[]} actions
|
||||
* The actions that will execute when the auto moderation rule is triggered
|
||||
* @property {boolean} [enabled] Whether the auto moderation rule should be enabled
|
||||
* @property {Collection<Snowflake, Role>|RoleResolvable[]} [exemptRoles]
|
||||
* The roles that should not be affected by the auto moderation rule
|
||||
* @property {Collection<Snowflake, GuildChannel|ThreadChannel>|GuildChannelResolvable[]} [exemptChannels]
|
||||
* The channels that should not be affected by the auto moderation rule
|
||||
* @property {string} [reason] The reason for creating the auto moderation rule
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new auto moderation rule.
|
||||
* @param {AutoModerationRuleCreateOptions} options Options for creating the auto moderation rule
|
||||
* @returns {Promise<AutoModerationRule>}
|
||||
*/
|
||||
async create({
|
||||
name,
|
||||
eventType,
|
||||
triggerType,
|
||||
triggerMetadata,
|
||||
actions,
|
||||
enabled,
|
||||
exemptRoles,
|
||||
exemptChannels,
|
||||
reason,
|
||||
}) {
|
||||
const data = await this.client.api.guilds(this.guild.id)['auto-moderation'].rules.post({
|
||||
data: {
|
||||
name,
|
||||
event_type: typeof eventType === 'number' ? eventType : AutoModerationRuleEventTypes[eventType],
|
||||
trigger_type: typeof triggerType === 'number' ? triggerType : AutoModerationRuleTriggerTypes[triggerType],
|
||||
trigger_metadata: triggerMetadata && {
|
||||
keyword_filter: triggerMetadata.keywordFilter,
|
||||
regex_patterns: triggerMetadata.regexPatterns,
|
||||
presets: triggerMetadata.presets?.map(preset =>
|
||||
typeof preset === 'number' ? preset : AutoModerationRuleKeywordPresetTypes[preset],
|
||||
),
|
||||
allow_list: triggerMetadata.allowList,
|
||||
mention_total_limit: triggerMetadata.mentionTotalLimit,
|
||||
},
|
||||
actions: actions.map(action => ({
|
||||
type: typeof action.type === 'number' ? action.type : AutoModerationActionTypes[action.type],
|
||||
metadata: {
|
||||
duration_seconds: action.metadata?.durationSeconds,
|
||||
channel_id: action.metadata?.channel && this.guild.channels.resolveId(action.metadata.channel),
|
||||
},
|
||||
})),
|
||||
enabled,
|
||||
exempt_roles: exemptRoles?.map(exemptRole => this.guild.roles.resolveId(exemptRole)),
|
||||
exempt_channels: exemptChannels?.map(exemptChannel => this.guild.channels.resolveId(exemptChannel)),
|
||||
},
|
||||
reason,
|
||||
});
|
||||
|
||||
return this._add(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Options used to edit an auto moderation rule.
|
||||
* @typedef {Object} AutoModerationRuleEditOptions
|
||||
* @property {string} [name] The name of the auto moderation rule
|
||||
* @property {AutoModerationRuleEventType} [eventType] The event type of the auto moderation rule
|
||||
* @property {AutoModerationTriggerMetadataOptions} [triggerMetadata] The trigger metadata of the auto moderation rule
|
||||
* @property {AutoModerationActionOptions[]} [actions]
|
||||
* The actions that will execute when the auto moderation rule is triggered
|
||||
* @property {boolean} [enabled] Whether the auto moderation rule should be enabled
|
||||
* @property {Collection<Snowflake, Role>|RoleResolvable[]} [exemptRoles]
|
||||
* The roles that should not be affected by the auto moderation rule
|
||||
* @property {Collection<Snowflake, GuildChannel|ThreadChannel>|GuildChannelResolvable[]} [exemptChannels]
|
||||
* The channels that should not be affected by the auto moderation rule
|
||||
* @property {string} [reason] The reason for creating the auto moderation rule
|
||||
*/
|
||||
|
||||
/**
|
||||
* Edits an auto moderation rule.
|
||||
* @param {AutoModerationRuleResolvable} autoModerationRule The auto moderation rule to edit
|
||||
* @param {AutoModerationRuleEditOptions} options Options for editing the auto moderation rule
|
||||
* @returns {Promise<AutoModerationRule>}
|
||||
*/
|
||||
async edit(
|
||||
autoModerationRule,
|
||||
{ name, eventType, triggerMetadata, actions, enabled, exemptRoles, exemptChannels, reason },
|
||||
) {
|
||||
const autoModerationRuleId = this.resolveId(autoModerationRule);
|
||||
|
||||
const data = await this.client.api
|
||||
.guilds(this.guild.id)('auto-moderation')
|
||||
.rules(autoModerationRuleId)
|
||||
.patch({
|
||||
data: {
|
||||
name,
|
||||
event_type: typeof eventType === 'number' ? eventType : AutoModerationRuleEventTypes[eventType],
|
||||
trigger_metadata: triggerMetadata && {
|
||||
keyword_filter: triggerMetadata.keywordFilter,
|
||||
regex_patterns: triggerMetadata.regexPatterns,
|
||||
presets: triggerMetadata.presets?.map(preset =>
|
||||
typeof preset === 'number' ? preset : AutoModerationRuleKeywordPresetTypes[preset],
|
||||
),
|
||||
allow_list: triggerMetadata.allowList,
|
||||
mention_total_limit: triggerMetadata.mentionTotalLimit,
|
||||
},
|
||||
actions: actions?.map(action => ({
|
||||
type: typeof action.type === 'number' ? action.type : AutoModerationActionTypes[action.type],
|
||||
metadata: {
|
||||
duration_seconds: action.metadata?.durationSeconds,
|
||||
channel_id: action.metadata?.channel && this.guild.channels.resolveId(action.metadata.channel),
|
||||
},
|
||||
})),
|
||||
enabled,
|
||||
exempt_roles: exemptRoles?.map(exemptRole => this.guild.roles.resolveId(exemptRole)),
|
||||
exempt_channels: exemptChannels?.map(exemptChannel => this.guild.channels.resolveId(exemptChannel)),
|
||||
},
|
||||
reason,
|
||||
});
|
||||
|
||||
return this._add(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data that can be resolved to give an AutoModerationRule object. This can be:
|
||||
* * An AutoModerationRule
|
||||
* * A Snowflake
|
||||
* @typedef {AutoModerationRule|Snowflake} AutoModerationRuleResolvable
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options used to fetch a single auto moderation rule from a guild.
|
||||
* @typedef {BaseFetchOptions} FetchAutoModerationRuleOptions
|
||||
* @property {AutoModerationRuleResolvable} autoModerationRule The auto moderation rule to fetch
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options used to fetch all auto moderation rules from a guild.
|
||||
* @typedef {Object} FetchAutoModerationRulesOptions
|
||||
* @property {boolean} [cache] Whether to cache the fetched auto moderation rules
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fetches auto moderation rules from Discord.
|
||||
* @param {AutoModerationRuleResolvable|FetchAutoModerationRuleOptions|FetchAutoModerationRulesOptions} [options]
|
||||
* Options for fetching auto moderation rule(s)
|
||||
* @returns {Promise<AutoModerationRule|Collection<Snowflake, AutoModerationRule>>}
|
||||
* @example
|
||||
* // Fetch all auto moderation rules from a guild without caching
|
||||
* guild.autoModerationRules.fetch({ cache: false })
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Fetch a single auto moderation rule
|
||||
* guild.autoModerationRules.fetch('979083472868098119')
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Fetch a single auto moderation rule without checking cache and without caching
|
||||
* guild.autoModerationRules.fetch({ autoModerationRule: '979083472868098119', cache: false, force: true })
|
||||
* .then(console.log)
|
||||
* .catch(console.error)
|
||||
*/
|
||||
fetch(options) {
|
||||
if (!options) return this._fetchMany();
|
||||
const { autoModerationRule, cache, force } = options;
|
||||
const resolvedAutoModerationRule = this.resolveId(autoModerationRule ?? options);
|
||||
if (resolvedAutoModerationRule) {
|
||||
return this._fetchSingle({ autoModerationRule: resolvedAutoModerationRule, cache, force });
|
||||
}
|
||||
return this._fetchMany(options);
|
||||
}
|
||||
|
||||
async _fetchSingle({ autoModerationRule, cache, force = false }) {
|
||||
if (!force) {
|
||||
const existing = this.cache.get(autoModerationRule);
|
||||
if (existing) return existing;
|
||||
}
|
||||
|
||||
const data = await this.client.api.guilds(this.guild.id)('auto-moderation').rules(autoModerationRule).get();
|
||||
return this._add(data, cache);
|
||||
}
|
||||
|
||||
async _fetchMany(options = {}) {
|
||||
const data = await this.client.api.guilds(this.guild.id)('auto-moderation').rules.get();
|
||||
|
||||
return data.reduce(
|
||||
(col, autoModerationRule) => col.set(autoModerationRule.id, this._add(autoModerationRule, options.cache)),
|
||||
new Collection(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an auto moderation rule.
|
||||
* @param {AutoModerationRuleResolvable} autoModerationRule The auto moderation rule to delete
|
||||
* @param {string} [reason] The reason for deleting the auto moderation rule
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async delete(autoModerationRule, reason) {
|
||||
const autoModerationRuleId = this.resolveId(autoModerationRule);
|
||||
await this.client.api.guilds(this.guild.id)('auto-moderation').rules(autoModerationRuleId).delete({ reason });
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AutoModerationRuleManager;
|
||||
@@ -50,9 +50,9 @@ class BaseGuildEmojiManager extends CachedManager {
|
||||
|
||||
/**
|
||||
* Data that can be resolved to give an emoji identifier. This can be:
|
||||
* * The unicode representation of an emoji
|
||||
* * The `<a:name:id>`, `<:name:id>`, `a:name:id` or `name:id` emoji identifier string of an emoji
|
||||
* * An EmojiResolvable
|
||||
* * The `<a:name:id>`, `<:name:id>`, `a:name:id` or `name:id` emoji identifier string of an emoji
|
||||
* * The Unicode representation of an emoji
|
||||
* @typedef {string|EmojiResolvable} EmojiIdentifierResolvable
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
const process = require('node:process');
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const CachedManager = require('./CachedManager');
|
||||
const { TypeError, Error } = require('../errors');
|
||||
const GuildBan = require('../structures/GuildBan');
|
||||
const { GuildMember } = require('../structures/GuildMember');
|
||||
|
||||
let deprecationEmittedForDays = false;
|
||||
|
||||
/**
|
||||
* Manages API methods for GuildBans and stores their cache.
|
||||
* @extends {CachedManager}
|
||||
@@ -54,9 +57,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
|
||||
* @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 +70,13 @@ class GuildBanManager extends CachedManager {
|
||||
* @param {UserResolvable|FetchBanOptions|FetchBansOptions} [options] Options for fetching guild ban(s)
|
||||
* @returns {Promise<GuildBan|Collection<Snowflake, GuildBan>>}
|
||||
* @example
|
||||
* // Fetch all bans from a guild
|
||||
* // Fetch multiple bans from a guild
|
||||
* guild.bans.fetch()
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Fetch all bans from a guild without caching
|
||||
* guild.bans.fetch({ cache: false })
|
||||
* // Fetch a maximum of 5 bans from a guild without caching
|
||||
* guild.bans.fetch({ limit: 5, cache: false })
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
@@ -91,14 +97,15 @@ class GuildBanManager extends CachedManager {
|
||||
*/
|
||||
fetch(options) {
|
||||
if (!options) return this._fetchMany();
|
||||
const user = this.client.users.resolveId(options);
|
||||
if (user) return this._fetchSingle({ user, cache: true });
|
||||
options.user &&= this.client.users.resolveId(options.user);
|
||||
if (!options.user) {
|
||||
if ('cache' in options) return this._fetchMany(options.cache);
|
||||
const { user, cache, force, limit, before, after } = options;
|
||||
const resolvedUser = this.client.users.resolveId(user ?? options);
|
||||
if (resolvedUser) return this._fetchSingle({ user: resolvedUser, cache, force });
|
||||
|
||||
if (!before && !after && !limit && typeof cache === 'undefined') {
|
||||
return Promise.reject(new Error('FETCH_BAN_RESOLVE_ID'));
|
||||
}
|
||||
return this._fetchSingle(options);
|
||||
|
||||
return this._fetchMany(options);
|
||||
}
|
||||
|
||||
async _fetchSingle({ user, cache, force = false }) {
|
||||
@@ -111,15 +118,20 @@ class GuildBanManager extends CachedManager {
|
||||
return this._add(data, cache);
|
||||
}
|
||||
|
||||
async _fetchMany(cache) {
|
||||
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());
|
||||
}
|
||||
async _fetchMany(options = {}) {
|
||||
const data = await this.client.api.guilds(this.guild.id).bans.get({
|
||||
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.
|
||||
* @typedef {Object} BanOptions
|
||||
* @property {number} [days=0] Number of days of messages to delete, must be between 0 and 7, inclusive
|
||||
* <warn>This property is deprecated. Use `deleteMessageSeconds` instead.</warn>
|
||||
* @property {number} [deleteMessageSeconds] Number of seconds of messages to delete,
|
||||
* must be between 0 and 604800 (7 days), inclusive
|
||||
* @property {string} [reason] The reason for the ban
|
||||
*/
|
||||
|
||||
@@ -136,15 +148,30 @@ class GuildBanManager extends CachedManager {
|
||||
* .then(banInfo => console.log(`Banned ${banInfo.user?.tag ?? banInfo.tag ?? banInfo}`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async create(user, options = { days: 0 }) {
|
||||
async create(user, options = {}) {
|
||||
if (typeof options !== 'object') throw new TypeError('INVALID_TYPE', 'options', 'object', true);
|
||||
const id = this.client.users.resolveId(user);
|
||||
if (!id) throw new Error('BAN_RESOLVE_ID', true);
|
||||
|
||||
if (typeof options.days !== 'undefined' && !deprecationEmittedForDays) {
|
||||
process.emitWarning(
|
||||
'The days option for GuildBanManager#create() is deprecated. Use the deleteMessageSeconds option instead.',
|
||||
'DeprecationWarning',
|
||||
);
|
||||
|
||||
deprecationEmittedForDays = true;
|
||||
}
|
||||
|
||||
await this.client.api
|
||||
.guilds(this.guild.id)
|
||||
.bans(id)
|
||||
.put({
|
||||
data: { delete_message_days: options.days },
|
||||
data: {
|
||||
delete_message_seconds:
|
||||
typeof options.deleteMessageSeconds !== 'undefined'
|
||||
? options.deleteMessageSeconds
|
||||
: (options.days ?? 0) * 24 * 60 * 60,
|
||||
},
|
||||
reason: options.reason,
|
||||
});
|
||||
if (user instanceof GuildMember) return user;
|
||||
|
||||
@@ -4,11 +4,22 @@ const process = require('node:process');
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const CachedManager = require('./CachedManager');
|
||||
const ThreadManager = require('./ThreadManager');
|
||||
const { Error } = require('../errors');
|
||||
const { Error, TypeError } = require('../errors');
|
||||
const GuildChannel = require('../structures/GuildChannel');
|
||||
const PermissionOverwrites = require('../structures/PermissionOverwrites');
|
||||
const ThreadChannel = require('../structures/ThreadChannel');
|
||||
const { ChannelTypes, ThreadChannelTypes } = require('../util/Constants');
|
||||
const Webhook = require('../structures/Webhook');
|
||||
const ChannelFlags = require('../util/ChannelFlags');
|
||||
const {
|
||||
ThreadChannelTypes,
|
||||
ChannelTypes,
|
||||
VideoQualityModes,
|
||||
SortOrderTypes,
|
||||
ForumLayoutTypes,
|
||||
} = require('../util/Constants');
|
||||
const DataResolver = require('../util/DataResolver');
|
||||
const Util = require('../util/Util');
|
||||
const { resolveAutoArchiveMaxLimit, transformGuildForumTag, transformGuildDefaultReaction } = require('../util/Util');
|
||||
|
||||
let cacheWarningEmitted = false;
|
||||
let storeChannelDeprecationEmitted = false;
|
||||
@@ -134,6 +145,11 @@ class GuildChannelManager extends CachedManager {
|
||||
position,
|
||||
rateLimitPerUser,
|
||||
rtcRegion,
|
||||
videoQualityMode,
|
||||
availableTags,
|
||||
defaultReactionEmoji,
|
||||
defaultSortOrder,
|
||||
defaultForumLayout,
|
||||
reason,
|
||||
} = {},
|
||||
) {
|
||||
@@ -141,6 +157,13 @@ class GuildChannelManager extends CachedManager {
|
||||
permissionOverwrites &&= permissionOverwrites.map(o => PermissionOverwrites.resolve(o, this.guild));
|
||||
const intType = typeof type === 'number' ? type : ChannelTypes[type] ?? ChannelTypes.GUILD_TEXT;
|
||||
|
||||
const videoMode = typeof videoQualityMode === 'number' ? videoQualityMode : VideoQualityModes[videoQualityMode];
|
||||
|
||||
const sortMode = typeof defaultSortOrder === 'number' ? defaultSortOrder : SortOrderTypes[defaultSortOrder];
|
||||
|
||||
const layoutMode =
|
||||
typeof defaultForumLayout === 'number' ? defaultForumLayout : ForumLayoutTypes[defaultForumLayout];
|
||||
|
||||
if (intType === ChannelTypes.GUILD_STORE && !storeChannelDeprecationEmitted) {
|
||||
storeChannelDeprecationEmitted = true;
|
||||
process.emitWarning(
|
||||
@@ -163,17 +186,198 @@ class GuildChannelManager extends CachedManager {
|
||||
permission_overwrites: permissionOverwrites,
|
||||
rate_limit_per_user: rateLimitPerUser,
|
||||
rtc_region: rtcRegion,
|
||||
video_quality_mode: videoMode,
|
||||
available_tags: availableTags?.map(availableTag => transformGuildForumTag(availableTag)),
|
||||
default_reaction_emoji: defaultReactionEmoji && transformGuildDefaultReaction(defaultReactionEmoji),
|
||||
default_sort_order: sortMode,
|
||||
default_forum_layout: layoutMode,
|
||||
},
|
||||
reason,
|
||||
});
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the target channel to a channel's followers.
|
||||
* @param {NewsChannel|Snowflake} channel The channel to follow
|
||||
* @param {TextChannelResolvable} targetChannel The channel where published announcements will be posted at
|
||||
* @param {string} [reason] Reason for creating the webhook
|
||||
* @returns {Promise<Snowflake>} Returns created target webhook id.
|
||||
*/
|
||||
async addFollower(channel, targetChannel, reason) {
|
||||
const channelId = this.resolveId(channel);
|
||||
const targetChannelId = this.resolveId(targetChannel);
|
||||
if (!channelId || !targetChannelId) throw new Error('GUILD_CHANNEL_RESOLVE');
|
||||
const { webhook_id } = await this.client.api.channels[channelId].followers.post({
|
||||
data: { webhook_channel_id: targetChannelId },
|
||||
reason,
|
||||
});
|
||||
return webhook_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @property {ChannelFlagsResolvable} [flags] The flags to set on the channel
|
||||
* @property {GuildForumTagData[]} [availableTags] The tags to set as available in a forum channel
|
||||
* @property {?DefaultReactionEmoji} [defaultReactionEmoji] The emoji to set as the default reaction emoji
|
||||
* @property {number} [defaultThreadRateLimitPerUser] The rate limit per user (slowmode) to set on forum posts
|
||||
* @property {?SortOrderType} [defaultSortOrder] The default sort order mode to set on 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,
|
||||
available_tags: data.availableTags?.map(availableTag => transformGuildForumTag(availableTag)),
|
||||
default_reaction_emoji: data.defaultReactionEmoji && transformGuildDefaultReaction(data.defaultReactionEmoji),
|
||||
default_thread_rate_limit_per_user: data.defaultThreadRateLimitPerUser,
|
||||
flags: 'flags' in data ? ChannelFlags.resolve(data.flags) : undefined,
|
||||
default_sort_order:
|
||||
typeof data.defaultSortOrder === 'string' ? SortOrderTypes[data.defaultSortOrder] : data.defaultSortOrder,
|
||||
},
|
||||
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.
|
||||
* @param {Snowflake} [id] The channel's id
|
||||
* @param {BaseFetchOptions} [options] Additional options for this fetch
|
||||
* @returns {Promise<?GuildChannel|Collection<Snowflake, GuildChannel>>}
|
||||
* @returns {Promise<?GuildChannel|ThreadChannel|Collection<Snowflake, ?GuildChannel>>}
|
||||
* @example
|
||||
* // Fetch all channels from the guild (excluding threads)
|
||||
* message.guild.channels.fetch()
|
||||
@@ -204,6 +408,39 @@ class GuildChannelManager extends CachedManager {
|
||||
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.
|
||||
* <info>Only one channel's parent can be changed at a time</info>
|
||||
@@ -219,7 +456,7 @@ class GuildChannelManager extends CachedManager {
|
||||
id: this.client.channels.resolveId(r.channel),
|
||||
position: r.position,
|
||||
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 });
|
||||
@@ -243,6 +480,23 @@ class GuildChannelManager extends CachedManager {
|
||||
const raw = await this.client.api.guilds(this.guild.id).threads.active.get();
|
||||
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;
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const BaseGuildEmojiManager = require('./BaseGuildEmojiManager');
|
||||
const { TypeError } = require('../errors');
|
||||
const { Error, TypeError } = require('../errors');
|
||||
const DataResolver = require('../util/DataResolver');
|
||||
const Permissions = require('../util/Permissions');
|
||||
|
||||
/**
|
||||
* 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));
|
||||
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.members;
|
||||
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;
|
||||
|
||||
90
src/managers/GuildForumThreadManager.js
Normal file
90
src/managers/GuildForumThreadManager.js
Normal file
@@ -0,0 +1,90 @@
|
||||
'use strict';
|
||||
|
||||
const ThreadManager = require('./ThreadManager');
|
||||
const { TypeError } = require('../errors');
|
||||
const MessagePayload = require('../structures/MessagePayload');
|
||||
const { resolveAutoArchiveMaxLimit } = require('../util/Util');
|
||||
|
||||
/**
|
||||
* Manages API methods for threads in forum channels and stores their cache.
|
||||
* @extends {ThreadManager}
|
||||
*/
|
||||
class GuildForumThreadManager extends ThreadManager {
|
||||
/**
|
||||
* The channel this Manager belongs to
|
||||
* @name GuildForumThreadManager#channel
|
||||
* @type {ForumChannel}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {BaseMessageOptions} GuildForumThreadMessageCreateOptions
|
||||
* @property {StickerResolvable} [stickers] The stickers to send with the message
|
||||
* @property {BitFieldResolvable} [flags] The flags to send with the message
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options for creating a thread.
|
||||
* @typedef {StartThreadOptions} GuildForumThreadCreateOptions
|
||||
* @property {GuildForumThreadMessageCreateOptions|MessagePayload} message The message associated with the thread post
|
||||
* @property {Snowflake[]} [appliedTags] The tags to apply to the thread
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new thread in the channel.
|
||||
* @param {GuildForumThreadCreateOptions} [options] Options to create a new thread
|
||||
* @returns {Promise<ThreadChannel>}
|
||||
* @example
|
||||
* // Create a new forum post
|
||||
* forum.threads
|
||||
* .create({
|
||||
* name: 'Food Talk',
|
||||
* autoArchiveDuration: 60,
|
||||
* message: {
|
||||
* content: 'Discuss your favorite food!',
|
||||
* },
|
||||
* reason: 'Needed a separate thread for food',
|
||||
* })
|
||||
* .then(threadChannel => console.log(threadChannel))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async create({
|
||||
name,
|
||||
autoArchiveDuration = this.channel.defaultAutoArchiveDuration,
|
||||
message,
|
||||
reason,
|
||||
rateLimitPerUser,
|
||||
appliedTags,
|
||||
} = {}) {
|
||||
if (!message) {
|
||||
throw new TypeError('GUILD_FORUM_MESSAGE_REQUIRED');
|
||||
}
|
||||
|
||||
let messagePayload;
|
||||
|
||||
if (message instanceof MessagePayload) {
|
||||
messagePayload = message.resolveData();
|
||||
} else {
|
||||
messagePayload = MessagePayload.create(this, message).resolveData();
|
||||
}
|
||||
|
||||
const { data: body, files } = await messagePayload.resolveFiles();
|
||||
|
||||
if (autoArchiveDuration === 'MAX') autoArchiveDuration = resolveAutoArchiveMaxLimit(this.channel.guild);
|
||||
|
||||
const data = await this.client.api.channels(this.channel.id).threads.post({
|
||||
data: {
|
||||
name,
|
||||
auto_archive_duration: autoArchiveDuration,
|
||||
rate_limit_per_user: rateLimitPerUser,
|
||||
applied_tags: appliedTags,
|
||||
message: body,
|
||||
},
|
||||
files,
|
||||
reason,
|
||||
});
|
||||
|
||||
return this.client.actions.ThreadCreate.handle(data).thread;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GuildForumThreadManager;
|
||||
@@ -18,6 +18,7 @@ const {
|
||||
VerificationLevels,
|
||||
DefaultMessageNotificationLevels,
|
||||
ExplicitContentFilterLevels,
|
||||
VideoQualityModes,
|
||||
} = require('../util/Constants');
|
||||
const DataResolver = require('../util/DataResolver');
|
||||
const Permissions = require('../util/Permissions');
|
||||
@@ -94,6 +95,7 @@ class GuildManager extends CachedManager {
|
||||
* @property {number} [bitrate] The bitrate of the voice channel
|
||||
* @property {number} [userLimit] The user limit 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]
|
||||
* Overwrites of the channel
|
||||
* @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;
|
||||
channel.rtc_region = 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;
|
||||
for (const overwrite of channel.permissionOverwrites) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable newline-per-chained-call */
|
||||
'use strict';
|
||||
|
||||
const { Buffer } = require('node:buffer');
|
||||
@@ -9,6 +10,8 @@ const BaseGuildVoiceChannel = require('../structures/BaseGuildVoiceChannel');
|
||||
const { GuildMember } = require('../structures/GuildMember');
|
||||
const { Role } = require('../structures/Role');
|
||||
const { Events, Opcodes } = require('../util/Constants');
|
||||
const { PartialTypes } = require('../util/Constants');
|
||||
const GuildMemberFlags = require('../util/GuildMemberFlags');
|
||||
const SnowflakeUtil = require('../util/SnowflakeUtil');
|
||||
|
||||
/**
|
||||
@@ -118,6 +121,20 @@ class GuildMemberManager extends CachedManager {
|
||||
return data instanceof Buffer ? (options.fetchWhenExisting === false ? null : this.fetch(userId)) : this._add(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* The client user as a GuildMember of this guild
|
||||
* @type {?GuildMember}
|
||||
* @readonly
|
||||
*/
|
||||
get me() {
|
||||
return (
|
||||
this.resolve(this.client.user.id) ??
|
||||
(this.client.options.partials.includes(PartialTypes.GUILD_MEMBER)
|
||||
? this._add({ user: { id: this.client.user.id } }, true)
|
||||
: null)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Options used to fetch a single member from a guild.
|
||||
* @typedef {BaseFetchOptions} FetchMemberOptions
|
||||
@@ -189,6 +206,15 @@ class GuildMemberManager extends CachedManager {
|
||||
return this._fetchMany(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the client user as a GuildMember of the guild.
|
||||
* @param {BaseFetchOptions} [options] The options for fetching the member
|
||||
* @returns {Promise<GuildMember>}
|
||||
*/
|
||||
fetchMe(options) {
|
||||
return this.fetch({ ...options, user: this.client.user.id });
|
||||
}
|
||||
|
||||
/**
|
||||
* Options used for searching guild members.
|
||||
* @typedef {Object} GuildSearchMembersOptions
|
||||
@@ -236,6 +262,7 @@ class GuildMemberManager extends CachedManager {
|
||||
* (if they are connected to voice), or `null` if you want to disconnect them from voice
|
||||
* @property {DateResolvable|null} [communicationDisabledUntil] The date or timestamp
|
||||
* for the member's communication to be disabled until. Provide `null` to enable communication again.
|
||||
* @property {GuildMemberFlagsResolvable} [flags] The flags to set for the member
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -268,6 +295,8 @@ class GuildMemberManager extends CachedManager {
|
||||
_data.communication_disabled_until =
|
||||
_data.communicationDisabledUntil && new Date(_data.communicationDisabledUntil).toISOString();
|
||||
|
||||
_data.flags = _data.flags && GuildMemberFlags.resolve(_data.flags);
|
||||
|
||||
let endpoint = this.client.api.guilds(this.guild.id);
|
||||
if (id === this.client.user.id) {
|
||||
const keys = Object.keys(data);
|
||||
@@ -353,7 +382,7 @@ class GuildMemberManager extends CachedManager {
|
||||
* @example
|
||||
* // Kick a user by id (or with a user/guild member object)
|
||||
* 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);
|
||||
*/
|
||||
async kick(user, reason) {
|
||||
@@ -376,10 +405,10 @@ class GuildMemberManager extends CachedManager {
|
||||
* @example
|
||||
* // Ban a user by id (or with a user/guild member object)
|
||||
* 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);
|
||||
*/
|
||||
ban(user, options = { days: 0 }) {
|
||||
ban(user, options) {
|
||||
return this.guild.bans.create(user, options);
|
||||
}
|
||||
|
||||
@@ -387,7 +416,7 @@ class GuildMemberManager extends CachedManager {
|
||||
* Unbans a user from the guild. Internally calls the {@link GuildBanManager#remove} method.
|
||||
* @param {UserResolvable} user The user to unban
|
||||
* @param {string} [reason] Reason for unbanning user
|
||||
* @returns {Promise<User>} The user that was unbanned
|
||||
* @returns {Promise<?User>} The user that was unbanned
|
||||
* @example
|
||||
* // Unban a user by id (or with a user/guild member object)
|
||||
* guild.members.unban('84484653687267328')
|
||||
@@ -408,6 +437,38 @@ class GuildMemberManager extends CachedManager {
|
||||
return this._add(data, cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a role to a member.
|
||||
* @param {GuildMemberResolvable} user The user to add the role from
|
||||
* @param {RoleResolvable} role The role to add
|
||||
* @param {string} [reason] Reason for adding the role
|
||||
* @returns {Promise<GuildMember|User|Snowflake>}
|
||||
*/
|
||||
async addRole(user, role, reason) {
|
||||
const userId = this.guild.members.resolveId(user);
|
||||
const roleId = this.guild.roles.resolveId(role);
|
||||
|
||||
await this.client.api.guilds(this.guild.id).members(userId).roles(roleId).put({ reason });
|
||||
|
||||
return this.resolve(user) ?? this.client.users.resolve(user) ?? userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a role from a member.
|
||||
* @param {UserResolvable} user The user to remove the role from
|
||||
* @param {RoleResolvable} role The role to remove
|
||||
* @param {string} [reason] Reason for removing the role
|
||||
* @returns {Promise<GuildMember|User|Snowflake>}
|
||||
*/
|
||||
async removeRole(user, role, reason) {
|
||||
const userId = this.guild.members.resolveId(user);
|
||||
const roleId = this.guild.roles.resolveId(role);
|
||||
|
||||
await this.client.api.guilds(this.guild.id).members(userId).roles(roleId).delete({ reason });
|
||||
|
||||
return this.resolve(user) ?? this.client.users.resolve(user) ?? userId;
|
||||
}
|
||||
|
||||
_fetchMany({
|
||||
limit = 0,
|
||||
withPresences: presences = false,
|
||||
|
||||
@@ -5,6 +5,7 @@ const CachedManager = require('./CachedManager');
|
||||
const { TypeError, Error } = require('../errors');
|
||||
const { GuildScheduledEvent } = require('../structures/GuildScheduledEvent');
|
||||
const { PrivacyLevels, GuildScheduledEventEntityTypes, GuildScheduledEventStatuses } = require('../util/Constants');
|
||||
const DataResolver = require('../util/DataResolver');
|
||||
|
||||
/**
|
||||
* 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
|
||||
* guild scheduled event
|
||||
* <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
|
||||
*/
|
||||
|
||||
@@ -76,6 +78,7 @@ class GuildScheduledEventManager extends CachedManager {
|
||||
scheduledEndTime,
|
||||
entityMetadata,
|
||||
reason,
|
||||
image,
|
||||
} = options;
|
||||
|
||||
if (typeof privacyLevel === 'string') privacyLevel = PrivacyLevels[privacyLevel];
|
||||
@@ -99,6 +102,7 @@ class GuildScheduledEventManager extends CachedManager {
|
||||
scheduled_start_time: new Date(scheduledStartTime).toISOString(),
|
||||
scheduled_end_time: scheduledEndTime ? new Date(scheduledEndTime).toISOString() : scheduledEndTime,
|
||||
description,
|
||||
image: image && (await DataResolver.resolveImage(image)),
|
||||
entity_type: entityType,
|
||||
entity_metadata,
|
||||
},
|
||||
@@ -172,6 +176,7 @@ class GuildScheduledEventManager extends CachedManager {
|
||||
* @property {GuildScheduledEventEntityMetadataOptions} [entityMetadata] The entity metadata of the
|
||||
* guild scheduled event
|
||||
* <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
|
||||
*/
|
||||
|
||||
@@ -197,6 +202,7 @@ class GuildScheduledEventManager extends CachedManager {
|
||||
scheduledEndTime,
|
||||
entityMetadata,
|
||||
reason,
|
||||
image,
|
||||
} = options;
|
||||
|
||||
if (typeof privacyLevel === 'string') privacyLevel = PrivacyLevels[privacyLevel];
|
||||
@@ -220,6 +226,7 @@ class GuildScheduledEventManager extends CachedManager {
|
||||
description,
|
||||
entity_type: entityType,
|
||||
status,
|
||||
image: image && (await DataResolver.resolveImage(image)),
|
||||
entity_metadata,
|
||||
},
|
||||
reason,
|
||||
|
||||
@@ -161,6 +161,19 @@ class GuildStickerManager extends CachedManager {
|
||||
const data = await this.client.api.guilds(this.guild.id).stickers.get();
|
||||
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;
|
||||
|
||||
98
src/managers/GuildTextThreadManager.js
Normal file
98
src/managers/GuildTextThreadManager.js
Normal file
@@ -0,0 +1,98 @@
|
||||
'use strict';
|
||||
|
||||
const ThreadManager = require('./ThreadManager');
|
||||
const { TypeError } = require('../errors');
|
||||
const { ChannelTypes } = require('../util/Constants');
|
||||
const { resolveAutoArchiveMaxLimit } = require('../util/Util');
|
||||
|
||||
/**
|
||||
* Manages API methods for {@link ThreadChannel} objects and stores their cache.
|
||||
* @extends {ThreadManager}
|
||||
*/
|
||||
class GuildTextThreadManager extends ThreadManager {
|
||||
/**
|
||||
* The channel this Manager belongs to
|
||||
* @name GuildTextThreadManager#channel
|
||||
* @type {TextChannel|NewsChannel}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options for creating a thread. <warn>Only one of `startMessage` or `type` can be defined.</warn>
|
||||
* @typedef {StartThreadOptions} GuildTextThreadCreateOptions
|
||||
* @property {MessageResolvable} [startMessage] The message to start a thread from. <warn>If this is defined then type
|
||||
* of thread gets automatically defined and cannot be changed. The provided `type` field will be ignored</warn>
|
||||
* @property {ThreadChannelTypes|number} [type] The type of thread to create. Defaults to `GUILD_PUBLIC_THREAD` if
|
||||
* created in a {@link TextChannel} <warn>When creating threads in a {@link NewsChannel} this is ignored and is always
|
||||
* `GUILD_NEWS_THREAD`</warn>
|
||||
* @property {boolean} [invitable] Whether non-moderators can add other non-moderators to the thread
|
||||
* <info>Can only be set when type will be `GUILD_PRIVATE_THREAD`</info>
|
||||
* @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the new channel in seconds
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new thread in the channel.
|
||||
* @param {GuildTextThreadCreateOptions} [options] Options to create a new thread
|
||||
* @returns {Promise<ThreadChannel>}
|
||||
* @example
|
||||
* // Create a new public thread
|
||||
* channel.threads
|
||||
* .create({
|
||||
* name: 'food-talk',
|
||||
* autoArchiveDuration: 60,
|
||||
* reason: 'Needed a separate thread for food',
|
||||
* })
|
||||
* .then(threadChannel => console.log(threadChannel))
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Create a new private thread
|
||||
* channel.threads
|
||||
* .create({
|
||||
* name: 'mod-talk',
|
||||
* autoArchiveDuration: 60,
|
||||
* type: 'GUILD_PRIVATE_THREAD',
|
||||
* reason: 'Needed a separate thread for moderation',
|
||||
* })
|
||||
* .then(threadChannel => console.log(threadChannel))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async create({
|
||||
name,
|
||||
autoArchiveDuration = this.channel.defaultAutoArchiveDuration,
|
||||
startMessage,
|
||||
type,
|
||||
invitable,
|
||||
reason,
|
||||
rateLimitPerUser,
|
||||
} = {}) {
|
||||
let path = this.client.api.channels(this.channel.id);
|
||||
if (type && typeof type !== 'string' && typeof type !== 'number') {
|
||||
throw new TypeError('INVALID_TYPE', 'type', 'ThreadChannelType or Number');
|
||||
}
|
||||
let resolvedType =
|
||||
this.channel.type === 'GUILD_NEWS' ? ChannelTypes.GUILD_NEWS_THREAD : ChannelTypes.GUILD_PUBLIC_THREAD;
|
||||
if (startMessage) {
|
||||
const startMessageId = this.channel.messages.resolveId(startMessage);
|
||||
if (!startMessageId) throw new TypeError('INVALID_TYPE', 'startMessage', 'MessageResolvable');
|
||||
path = path.messages(startMessageId);
|
||||
} else if (this.channel.type !== 'GUILD_NEWS') {
|
||||
resolvedType = typeof type === 'string' ? ChannelTypes[type] : type ?? resolvedType;
|
||||
}
|
||||
|
||||
if (autoArchiveDuration === 'MAX') autoArchiveDuration = resolveAutoArchiveMaxLimit(this.channel.guild);
|
||||
|
||||
const data = await path.threads.post({
|
||||
data: {
|
||||
name,
|
||||
auto_archive_duration: autoArchiveDuration,
|
||||
type: resolvedType,
|
||||
invitable: resolvedType === ChannelTypes.GUILD_PRIVATE_THREAD ? invitable : undefined,
|
||||
rate_limit_per_user: rateLimitPerUser,
|
||||
},
|
||||
reason,
|
||||
});
|
||||
|
||||
return this.client.actions.ThreadCreate.handle(data).thread;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GuildTextThreadManager;
|
||||
@@ -156,25 +156,27 @@ class MessageManager extends CachedManager {
|
||||
/**
|
||||
* Pins a message to the channel's pinned messages, even if it's not cached.
|
||||
* @param {MessageResolvable} message The message to pin
|
||||
* @param {string} [reason] Reason for pinning
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async pin(message) {
|
||||
async pin(message, reason) {
|
||||
message = this.resolveId(message);
|
||||
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.
|
||||
* @param {MessageResolvable} message The message to unpin
|
||||
* @param {string} [reason] Reason for unpinning
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async unpin(message) {
|
||||
async unpin(message, reason) {
|
||||
message = this.resolveId(message);
|
||||
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);
|
||||
*/
|
||||
edit(userOrRole, options, overwriteOptions) {
|
||||
userOrRole = this.channel.guild.roles.resolveId(userOrRole) ?? this.client.users.resolveId(userOrRole);
|
||||
const existing = this.cache.get(userOrRole);
|
||||
const existing = this.cache.get(
|
||||
this.channel.guild.roles.resolveId(userOrRole) ?? this.client.users.resolveId(userOrRole),
|
||||
);
|
||||
return this.upsert(userOrRole, options, overwriteOptions, existing);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ class ReactionManager extends CachedManager {
|
||||
* Data that can be resolved to a MessageReaction object. This can be:
|
||||
* * A MessageReaction
|
||||
* * A Snowflake
|
||||
* * The Unicode representation of an emoji
|
||||
* @typedef {MessageReaction|Snowflake} MessageReactionResolvable
|
||||
*/
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ const { TypeError } = require('../errors');
|
||||
const { Role } = require('../structures/Role');
|
||||
const DataResolver = require('../util/DataResolver');
|
||||
const Permissions = require('../util/Permissions');
|
||||
const { resolveColor, setPosition } = require('../util/Util');
|
||||
const { resolveColor } = require('../util/Util');
|
||||
const Util = require('../util/Util');
|
||||
|
||||
let cacheWarningEmitted = false;
|
||||
|
||||
@@ -159,7 +160,7 @@ class RoleManager extends CachedManager {
|
||||
guild_id: this.guild.id,
|
||||
role: data,
|
||||
});
|
||||
if (position) return role.setPosition(position, reason);
|
||||
if (position) return this.setPosition(role, position, { reason });
|
||||
return role;
|
||||
}
|
||||
|
||||
@@ -179,21 +180,7 @@ class RoleManager extends CachedManager {
|
||||
role = this.resolve(role);
|
||||
if (!role) throw new TypeError('INVALID_TYPE', 'role', 'RoleResolvable');
|
||||
|
||||
if (typeof data.position === 'number') {
|
||||
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,
|
||||
});
|
||||
}
|
||||
if (typeof data.position === 'number') await this.setPosition(role, data.position, { reason });
|
||||
|
||||
let icon = data.icon;
|
||||
if (icon) {
|
||||
@@ -227,7 +214,7 @@ class RoleManager extends CachedManager {
|
||||
* @example
|
||||
* // Delete a role
|
||||
* 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);
|
||||
*/
|
||||
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 });
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param {GuildRolePosition[]} rolePositions Role positions to update
|
||||
|
||||
@@ -31,6 +31,7 @@ class StageInstanceManager extends CachedManager {
|
||||
* @typedef {Object} StageInstanceCreateOptions
|
||||
* @property {string} topic The topic 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);
|
||||
if (!channelId) throw new Error('STAGE_CHANNEL_RESOLVE');
|
||||
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];
|
||||
|
||||
@@ -67,6 +68,7 @@ class StageInstanceManager extends CachedManager {
|
||||
channel_id: channelId,
|
||||
topic,
|
||||
privacy_level: privacyLevel,
|
||||
send_start_notification: sendStartNotification,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ const { Collection } = require('@discordjs/collection');
|
||||
const CachedManager = require('./CachedManager');
|
||||
const { TypeError } = require('../errors');
|
||||
const ThreadChannel = require('../structures/ThreadChannel');
|
||||
const { ChannelTypes } = require('../util/Constants');
|
||||
|
||||
/**
|
||||
* Manages API methods for {@link ThreadChannel} objects and stores their cache.
|
||||
@@ -59,90 +58,6 @@ class ThreadManager extends CachedManager {
|
||||
* @returns {?Snowflake}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options for creating a thread. <warn>Only one of `startMessage` or `type` can be defined.</warn>
|
||||
* @typedef {StartThreadOptions} ThreadCreateOptions
|
||||
* @property {MessageResolvable} [startMessage] The message to start a thread from. <warn>If this is defined then type
|
||||
* of thread gets automatically defined and cannot be changed. The provided `type` field will be ignored</warn>
|
||||
* @property {ThreadChannelTypes|number} [type] The type of thread to create. Defaults to `GUILD_PUBLIC_THREAD` if
|
||||
* created in a {@link TextChannel} <warn>When creating threads in a {@link NewsChannel} this is ignored and is always
|
||||
* `GUILD_NEWS_THREAD`</warn>
|
||||
* @property {boolean} [invitable] Whether non-moderators can add other non-moderators to the thread
|
||||
* <info>Can only be set when type will be `GUILD_PRIVATE_THREAD`</info>
|
||||
* @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the new channel in seconds
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new thread in the channel.
|
||||
* @param {ThreadCreateOptions} [options] Options to create a new thread
|
||||
* @returns {Promise<ThreadChannel>}
|
||||
* @example
|
||||
* // Create a new public thread
|
||||
* channel.threads
|
||||
* .create({
|
||||
* name: 'food-talk',
|
||||
* autoArchiveDuration: 60,
|
||||
* reason: 'Needed a separate thread for food',
|
||||
* })
|
||||
* .then(threadChannel => console.log(threadChannel))
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Create a new private thread
|
||||
* channel.threads
|
||||
* .create({
|
||||
* name: 'mod-talk',
|
||||
* autoArchiveDuration: 60,
|
||||
* type: 'GUILD_PRIVATE_THREAD',
|
||||
* reason: 'Needed a separate thread for moderation',
|
||||
* })
|
||||
* .then(threadChannel => console.log(threadChannel))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async create({
|
||||
name,
|
||||
autoArchiveDuration = this.channel.defaultAutoArchiveDuration,
|
||||
startMessage,
|
||||
type,
|
||||
invitable,
|
||||
reason,
|
||||
rateLimitPerUser,
|
||||
} = {}) {
|
||||
let path = this.client.api.channels(this.channel.id);
|
||||
if (type && typeof type !== 'string' && typeof type !== 'number') {
|
||||
throw new TypeError('INVALID_TYPE', 'type', 'ThreadChannelType or Number');
|
||||
}
|
||||
let resolvedType =
|
||||
this.channel.type === 'GUILD_NEWS' ? ChannelTypes.GUILD_NEWS_THREAD : ChannelTypes.GUILD_PUBLIC_THREAD;
|
||||
if (startMessage) {
|
||||
const startMessageId = this.channel.messages.resolveId(startMessage);
|
||||
if (!startMessageId) throw new TypeError('INVALID_TYPE', 'startMessage', 'MessageResolvable');
|
||||
path = path.messages(startMessageId);
|
||||
} else if (this.channel.type !== 'GUILD_NEWS') {
|
||||
resolvedType = typeof type === 'string' ? ChannelTypes[type] : type ?? resolvedType;
|
||||
}
|
||||
if (autoArchiveDuration === 'MAX') {
|
||||
autoArchiveDuration = 1440;
|
||||
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({
|
||||
data: {
|
||||
name,
|
||||
auto_archive_duration: autoArchiveDuration,
|
||||
type: resolvedType,
|
||||
invitable: resolvedType === ChannelTypes.GUILD_PRIVATE_THREAD ? invitable : undefined,
|
||||
rate_limit_per_user: rateLimitPerUser,
|
||||
},
|
||||
reason,
|
||||
});
|
||||
|
||||
return this.client.actions.ThreadCreate.handle(data).thread;
|
||||
}
|
||||
|
||||
/**
|
||||
* The options for fetching multiple threads, the properties are mutually exclusive
|
||||
* @typedef {Object} FetchThreadsOptions
|
||||
|
||||
@@ -36,6 +36,24 @@ class ThreadMemberManager extends CachedManager {
|
||||
return member;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the client user as a ThreadMember of the thread.
|
||||
* @param {BaseFetchOptions} [options] The options for fetching the member
|
||||
* @returns {Promise<ThreadMember>}
|
||||
*/
|
||||
fetchMe(options) {
|
||||
return this.fetch(this.client.user.id, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* The client user as a ThreadMember of this ThreadChannel
|
||||
* @type {?ThreadMember}
|
||||
* @readonly
|
||||
*/
|
||||
get me() {
|
||||
return this.resolve(this.client.user.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data that resolves to give a ThreadMember object. This can be:
|
||||
* * A ThreadMember object
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const CachedManager = require('./CachedManager');
|
||||
const { Error } = require('../errors');
|
||||
const { GuildMember } = require('../structures/GuildMember');
|
||||
const { Message } = require('../structures/Message');
|
||||
const ThreadMember = require('../structures/ThreadMember');
|
||||
|
||||
@@ -15,7 +15,7 @@ class RateLimitError extends Error {
|
||||
this.name = 'RateLimitError';
|
||||
|
||||
/**
|
||||
* Time until this rate limit ends, in ms
|
||||
* Time until this rate limit ends, in milliseconds
|
||||
* @type {number}
|
||||
*/
|
||||
this.timeout = timeout;
|
||||
|
||||
@@ -280,7 +280,7 @@ class RequestHandler {
|
||||
/**
|
||||
* @typedef {Object} InvalidRequestWarningData
|
||||
* @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
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,7 +14,7 @@ let Worker = null;
|
||||
* A self-contained shard created by the {@link ShardingManager}. Each one has a {@link ChildProcess} that contains
|
||||
* an instance of the bot and its {@link Client}. When its child process/worker exits for any reason, the shard will
|
||||
* spawn a new one to replace it as necessary.
|
||||
* @extends EventEmitter
|
||||
* @extends {EventEmitter}
|
||||
*/
|
||||
class Shard extends EventEmitter {
|
||||
constructor(manager, id) {
|
||||
@@ -249,14 +249,18 @@ class Shard extends EventEmitter {
|
||||
const listener = message => {
|
||||
if (message?._fetchProp !== prop) return;
|
||||
child.removeListener('message', listener);
|
||||
this.decrementMaxListeners(child);
|
||||
this._fetches.delete(prop);
|
||||
if (!message._error) resolve(message._result);
|
||||
else reject(Util.makeError(message._error));
|
||||
};
|
||||
|
||||
this.incrementMaxListeners(child);
|
||||
child.on('message', listener);
|
||||
|
||||
this.send({ _fetchProp: prop }).catch(err => {
|
||||
child.removeListener('message', listener);
|
||||
this.decrementMaxListeners(child);
|
||||
this._fetches.delete(prop);
|
||||
reject(err);
|
||||
});
|
||||
@@ -288,14 +292,18 @@ class Shard extends EventEmitter {
|
||||
const listener = message => {
|
||||
if (message?._eval !== _eval) return;
|
||||
child.removeListener('message', listener);
|
||||
this.decrementMaxListeners(child);
|
||||
this._evals.delete(_eval);
|
||||
if (!message._error) resolve(message._result);
|
||||
else reject(Util.makeError(message._error));
|
||||
};
|
||||
|
||||
this.incrementMaxListeners(child);
|
||||
child.on('message', listener);
|
||||
|
||||
this.send({ _eval }).catch(err => {
|
||||
child.removeListener('message', listener);
|
||||
this.decrementMaxListeners(child);
|
||||
this._evals.delete(_eval);
|
||||
reject(err);
|
||||
});
|
||||
@@ -406,6 +414,30 @@ class Shard extends EventEmitter {
|
||||
|
||||
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;
|
||||
|
||||
@@ -111,13 +111,16 @@ class ShardClientUtil {
|
||||
const listener = message => {
|
||||
if (message?._sFetchProp !== prop || message._sFetchPropShard !== shard) return;
|
||||
parent.removeListener('message', listener);
|
||||
this.decrementMaxListeners(parent);
|
||||
if (!message._error) resolve(message._result);
|
||||
else reject(Util.makeError(message._error));
|
||||
};
|
||||
this.incrementMaxListeners(parent);
|
||||
parent.on('message', listener);
|
||||
|
||||
this.send({ _sFetchProp: prop, _sFetchPropShard: shard }).catch(err => {
|
||||
parent.removeListener('message', listener);
|
||||
this.decrementMaxListeners(parent);
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
@@ -146,13 +149,15 @@ class ShardClientUtil {
|
||||
const listener = message => {
|
||||
if (message?._sEval !== script || message._sEvalShard !== options.shard) return;
|
||||
parent.removeListener('message', listener);
|
||||
this.decrementMaxListeners(parent);
|
||||
if (!message._error) resolve(message._result);
|
||||
else reject(Util.makeError(message._error));
|
||||
};
|
||||
this.incrementMaxListeners(parent);
|
||||
parent.on('message', listener);
|
||||
|
||||
this.send({ _sEval: script, _sEvalShard: options.shard }).catch(err => {
|
||||
parent.removeListener('message', listener);
|
||||
this.decrementMaxListeners(parent);
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
@@ -241,6 +246,30 @@ class ShardClientUtil {
|
||||
if (shard < 0) throw new Error('SHARDING_SHARD_MISCALCULATION', shard, guildId, shardCount);
|
||||
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;
|
||||
|
||||
@@ -36,7 +36,7 @@ class ShardingManager extends EventEmitter {
|
||||
* @property {boolean} [respawn=true] Whether shards should automatically respawn upon exiting
|
||||
* @property {string[]} [shardArgs=[]] Arguments to pass to the shard script when spawning
|
||||
* (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')
|
||||
* @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];
|
||||
}
|
||||
|
||||
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 ApplicationCommandPermissionsManager = require('../managers/ApplicationCommandPermissionsManager');
|
||||
const { ApplicationCommandOptionTypes, ApplicationCommandTypes, ChannelTypes } = require('../util/Constants');
|
||||
const Permissions = require('../util/Permissions');
|
||||
const SnowflakeUtil = require('../util/SnowflakeUtil');
|
||||
|
||||
/**
|
||||
@@ -62,6 +63,26 @@ class ApplicationCommand extends Base {
|
||||
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) {
|
||||
/**
|
||||
* The description of this command
|
||||
@@ -70,6 +91,26 @@ class ApplicationCommand extends Base {
|
||||
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) {
|
||||
/**
|
||||
* The options of this command
|
||||
@@ -80,13 +121,39 @@ class ApplicationCommand extends Base {
|
||||
this.options ??= [];
|
||||
}
|
||||
|
||||
/* eslint-disable max-len */
|
||||
if ('default_permission' in data) {
|
||||
/**
|
||||
* Whether the command is enabled by default when the app is added to a guild
|
||||
* @type {boolean}
|
||||
* @deprecated Use {@link ApplicationCommand.defaultMemberPermissions} and {@link ApplicationCommand.dmPermission} instead.
|
||||
*/
|
||||
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) {
|
||||
/**
|
||||
@@ -128,10 +195,15 @@ class ApplicationCommand extends Base {
|
||||
* Data for creating or editing an application command.
|
||||
* @typedef {Object} ApplicationCommandData
|
||||
* @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 {Object<Locale, string>} [descriptionLocalizations] The localizations for the command description
|
||||
* @property {ApplicationCommandType} [type] The type of 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 {?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
|
||||
* @property {ApplicationCommandOptionType|number} type The type 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 {Object<Locale, string>} [descriptionLocalizations] The description localizations for the option
|
||||
* @property {boolean} [autocomplete] Whether the option is an autocomplete option
|
||||
* @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 {ChannelType[]|number[]} [channelTypes] When the option type is channel,
|
||||
* the allowed types of channels that can be selected
|
||||
* @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} [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.
|
||||
* @param {ApplicationCommandData} data The data to update the command with
|
||||
* @param {Partial<ApplicationCommandData>} data The data to update the command with
|
||||
* @returns {Promise<ApplicationCommand>}
|
||||
* @example
|
||||
* // Edit the description of this command
|
||||
@@ -179,6 +264,23 @@ class ApplicationCommand extends Base {
|
||||
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
|
||||
* @param {string} description The new description of the command
|
||||
@@ -188,14 +290,52 @@ class ApplicationCommand extends Base {
|
||||
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
|
||||
* @param {boolean} [defaultPermission=true] The default permission for this command
|
||||
* @returns {Promise<ApplicationCommand>}
|
||||
* @deprecated Use {@link ApplicationCommand#setDefaultMemberPermissions} and {@link ApplicationCommand#setDMPermission} instead.
|
||||
*/
|
||||
setDefaultPermission(defaultPermission = true) {
|
||||
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
|
||||
@@ -232,6 +372,20 @@ class ApplicationCommand extends Base {
|
||||
// If given an id, check if the id matches
|
||||
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
|
||||
const commandType = typeof command.type === 'string' ? command.type : ApplicationCommandTypes[command.type];
|
||||
if (
|
||||
@@ -240,6 +394,8 @@ class ApplicationCommand extends Base {
|
||||
('version' in command && command.version !== this.version) ||
|
||||
('autocomplete' in command && command.autocomplete !== this.autocomplete) ||
|
||||
(commandType && commandType !== this.type) ||
|
||||
defaultMemberPermissions !== (this.defaultMemberPermissions?.bitfield ?? null) ||
|
||||
(typeof dmPermission !== 'undefined' && dmPermission !== this.dmPermission) ||
|
||||
// Future proof for options being nullable
|
||||
// TODO: remove ?? 0 on each when nullable
|
||||
(command.options?.length ?? 0) !== (this.options?.length ?? 0) ||
|
||||
@@ -301,7 +457,9 @@ class ApplicationCommand extends Base {
|
||||
option.options?.length !== existing.options?.length ||
|
||||
(option.channelTypes ?? option.channel_types)?.length !== existing.channelTypes?.length ||
|
||||
(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;
|
||||
}
|
||||
@@ -344,7 +502,11 @@ class ApplicationCommand extends Base {
|
||||
* @typedef {Object} ApplicationCommandOption
|
||||
* @property {ApplicationCommandOptionType} type The type 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 {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} [autocomplete] Whether the option is an autocomplete option
|
||||
* @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
|
||||
* @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} [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.
|
||||
* @typedef {Object} ApplicationCommandOptionChoice
|
||||
* @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
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @returns {APIApplicationCommandOption}
|
||||
* @private
|
||||
@@ -374,14 +542,29 @@ class ApplicationCommand extends Base {
|
||||
const channelTypesKey = received ? 'channelTypes' : 'channel_types';
|
||||
const minValueKey = received ? 'minValue' : 'min_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 {
|
||||
type: typeof option.type === 'number' && !received ? option.type : ApplicationCommandOptionTypes[option.type],
|
||||
name: option.name,
|
||||
[nameLocalizationsKey]: option.nameLocalizations ?? option.name_localizations,
|
||||
[nameLocalizedKey]: option.nameLocalized ?? option.name_localized,
|
||||
description: option.description,
|
||||
[descriptionLocalizationsKey]: option.descriptionLocalizations ?? option.description_localizations,
|
||||
[descriptionLocalizedKey]: option.descriptionLocalized ?? option.description_localized,
|
||||
required:
|
||||
option.required ?? (stringType === 'SUB_COMMAND' || stringType === 'SUB_COMMAND_GROUP' ? undefined : false),
|
||||
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)),
|
||||
[channelTypesKey]: received
|
||||
? option.channel_types?.map(type => ChannelTypes[type])
|
||||
@@ -390,6 +573,8 @@ class ApplicationCommand extends Base {
|
||||
option.channel_types,
|
||||
[minValueKey]: option.minValue ?? option.min_value,
|
||||
[maxValueKey]: option.maxValue ?? option.max_value,
|
||||
[minLengthKey]: option.minLength ?? option.min_length,
|
||||
[maxLengthKey]: option.maxLength ?? option.max_length,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
48
src/structures/ApplicationRoleConnectionMetadata.js
Normal file
48
src/structures/ApplicationRoleConnectionMetadata.js
Normal file
@@ -0,0 +1,48 @@
|
||||
'use strict';
|
||||
|
||||
const { ApplicationRoleConnectionMetadataTypes } = require('../util/Constants');
|
||||
|
||||
/**
|
||||
* Role connection metadata object for an application.
|
||||
*/
|
||||
class ApplicationRoleConnectionMetadata {
|
||||
constructor(data) {
|
||||
/**
|
||||
* The name of this metadata field
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = data.name;
|
||||
|
||||
/**
|
||||
* The name localizations for this metadata field
|
||||
* @type {?Object<Locale, string>}
|
||||
*/
|
||||
this.nameLocalizations = data.name_localizations ?? null;
|
||||
|
||||
/**
|
||||
* The description of this metadata field
|
||||
* @type {string}
|
||||
*/
|
||||
this.description = data.description;
|
||||
|
||||
/**
|
||||
* The description localizations for this metadata field
|
||||
* @type {?Object<Locale, string>}
|
||||
*/
|
||||
this.descriptionLocalizations = data.description_localizations ?? null;
|
||||
|
||||
/**
|
||||
* The dictionary key for this metadata field
|
||||
* @type {string}
|
||||
*/
|
||||
this.key = data.key;
|
||||
|
||||
/**
|
||||
* The type of this metadata field
|
||||
* @type {ApplicationRoleConnectionMetadataType}
|
||||
*/
|
||||
this.type = typeof data.type === 'number' ? ApplicationRoleConnectionMetadataTypes[data.type] : data.type;
|
||||
}
|
||||
}
|
||||
|
||||
exports.ApplicationRoleConnectionMetadata = ApplicationRoleConnectionMetadata;
|
||||
89
src/structures/AutoModerationActionExecution.js
Normal file
89
src/structures/AutoModerationActionExecution.js
Normal file
@@ -0,0 +1,89 @@
|
||||
'use strict';
|
||||
|
||||
const { AutoModerationRuleTriggerTypes } = require('../util/Constants');
|
||||
|
||||
/**
|
||||
* Represents the structure of an executed action when an {@link AutoModerationRule} is triggered.
|
||||
*/
|
||||
class AutoModerationActionExecution {
|
||||
constructor(data, guild) {
|
||||
/**
|
||||
* The guild where this action was executed from.
|
||||
* @type {Guild}
|
||||
*/
|
||||
this.guild = guild;
|
||||
|
||||
/**
|
||||
* The action that was executed.
|
||||
* @type {AutoModerationAction}
|
||||
*/
|
||||
this.action = data.action;
|
||||
|
||||
/**
|
||||
* The id of the auto moderation rule this action belongs to.
|
||||
* @type {Snowflake}
|
||||
*/
|
||||
this.ruleId = data.rule_id;
|
||||
|
||||
/**
|
||||
* The trigger type of the auto moderation rule which was triggered.
|
||||
* @type {AutoModerationRuleTriggerType}
|
||||
*/
|
||||
this.ruleTriggerType = AutoModerationRuleTriggerTypes[data.rule_trigger_type];
|
||||
|
||||
/**
|
||||
* The id of the user that triggered this action.
|
||||
* @type {Snowflake}
|
||||
*/
|
||||
this.userId = data.user_id;
|
||||
|
||||
/**
|
||||
* The id of the channel where this action was triggered from.
|
||||
* @type {?Snowflake}
|
||||
*/
|
||||
this.channelId = data.channel_id ?? null;
|
||||
|
||||
/**
|
||||
* The id of the message that triggered this action.
|
||||
* @type {?Snowflake}
|
||||
* <info>This will not be present if the message was blocked or the content was not part of any message.</info>
|
||||
*/
|
||||
this.messageId = data.message_id ?? null;
|
||||
|
||||
/**
|
||||
* The id of any system auto moderation messages posted as a result of this action.
|
||||
* @type {?Snowflake}
|
||||
*/
|
||||
this.alertSystemMessageId = data.alert_system_message_id ?? null;
|
||||
|
||||
/**
|
||||
* The content that triggered this action.
|
||||
* <info>This property requires the {@link Intents.FLAGS.MESSAGE_CONTENT} privileged gateway intent.</info>
|
||||
* @type {string}
|
||||
*/
|
||||
this.content = data.content;
|
||||
|
||||
/**
|
||||
* The word or phrase configured in the rule that triggered this action.
|
||||
* @type {?string}
|
||||
*/
|
||||
this.matchedKeyword = data.matched_keyword ?? null;
|
||||
|
||||
/**
|
||||
* The substring in content that triggered this action.
|
||||
* @type {?string}
|
||||
*/
|
||||
this.matchedContent = data.matched_content ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The auto moderation rule this action belongs to.
|
||||
* @type {?AutoModerationRule}
|
||||
* @readonly
|
||||
*/
|
||||
get autoModerationRule() {
|
||||
return this.guild.autoModerationRules.cache.get(this.ruleId) ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AutoModerationActionExecution;
|
||||
279
src/structures/AutoModerationRule.js
Normal file
279
src/structures/AutoModerationRule.js
Normal file
@@ -0,0 +1,279 @@
|
||||
'use strict';
|
||||
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const Base = require('./Base');
|
||||
const {
|
||||
AutoModerationRuleKeywordPresetTypes,
|
||||
AutoModerationRuleTriggerTypes,
|
||||
AutoModerationRuleEventTypes,
|
||||
AutoModerationActionTypes,
|
||||
} = require('../util/Constants');
|
||||
|
||||
/**
|
||||
* Represents an auto moderation rule.
|
||||
* @extends {Base}
|
||||
*/
|
||||
class AutoModerationRule extends Base {
|
||||
constructor(client, data, guild) {
|
||||
super(client);
|
||||
|
||||
/**
|
||||
* The id of this auto moderation rule.
|
||||
* @type {Snowflake}
|
||||
*/
|
||||
this.id = data.id;
|
||||
|
||||
/**
|
||||
* The guild this auto moderation rule is for.
|
||||
* @type {Guild}
|
||||
*/
|
||||
this.guild = guild;
|
||||
|
||||
/**
|
||||
* The user that created this auto moderation rule.
|
||||
* @type {Snowflake}
|
||||
*/
|
||||
this.creatorId = data.creator_id;
|
||||
|
||||
/**
|
||||
* The trigger type of this auto moderation rule.
|
||||
* @type {AutoModerationRuleTriggerType}
|
||||
*/
|
||||
this.triggerType = AutoModerationRuleTriggerTypes[data.trigger_type];
|
||||
|
||||
this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
if ('name' in data) {
|
||||
/**
|
||||
* The name of this auto moderation rule.
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = data.name;
|
||||
}
|
||||
|
||||
if ('event_type' in data) {
|
||||
/**
|
||||
* The event type of this auto moderation rule.
|
||||
* @type {AutoModerationRuleEventType}
|
||||
*/
|
||||
this.eventType = AutoModerationRuleEventTypes[data.event_type];
|
||||
}
|
||||
|
||||
if ('trigger_metadata' in data) {
|
||||
/**
|
||||
* Additional data used to determine whether an auto moderation rule should be triggered.
|
||||
* @typedef {Object} AutoModerationTriggerMetadata
|
||||
* @property {string[]} keywordFilter The substrings that will be searched for in the content
|
||||
* @property {string[]} regexPatterns The regular expression patterns which will be matched against the content
|
||||
* <info>Only Rust-flavored regular expressions are supported.</info>
|
||||
* @property {AutoModerationRuleKeywordPresetType[]} presets
|
||||
* The internally pre-defined wordsets which will be searched for in the content
|
||||
* @property {string[]} allowList The substrings that will be exempt from triggering
|
||||
* {@link AutoModerationRuleTriggerTypes.KEYWORD} and {@link AutoModerationRuleTriggerTypes.KEYWORD_PRESET}
|
||||
* @property {?number} mentionTotalLimit The total number of role & user mentions allowed per message
|
||||
*/
|
||||
|
||||
/**
|
||||
* The trigger metadata of the rule.
|
||||
* @type {AutoModerationTriggerMetadata}
|
||||
*/
|
||||
this.triggerMetadata = {
|
||||
keywordFilter: data.trigger_metadata.keyword_filter ?? [],
|
||||
regexPatterns: data.trigger_metadata.regex_patterns ?? [],
|
||||
presets: data.trigger_metadata.presets?.map(preset => AutoModerationRuleKeywordPresetTypes[preset]) ?? [],
|
||||
allowList: data.trigger_metadata.allow_list ?? [],
|
||||
mentionTotalLimit: data.trigger_metadata.mention_total_limit ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
if ('actions' in data) {
|
||||
/**
|
||||
* An object containing information about an auto moderation rule action.
|
||||
* @typedef {Object} AutoModerationAction
|
||||
* @property {AutoModerationActionType} type The type of this auto moderation rule action
|
||||
* @property {AutoModerationActionMetadata} metadata Additional metadata needed during execution
|
||||
*/
|
||||
|
||||
/**
|
||||
* Additional data used when an auto moderation rule is executed.
|
||||
* @typedef {Object} AutoModerationActionMetadata
|
||||
* @property {?Snowflake} channelId The id of the channel to which content will be logged
|
||||
* @property {?number} durationSeconds The timeout duration in seconds
|
||||
*/
|
||||
|
||||
/**
|
||||
* The actions of this auto moderation rule.
|
||||
* @type {AutoModerationAction[]}
|
||||
*/
|
||||
this.actions = data.actions.map(action => ({
|
||||
type: AutoModerationActionTypes[action.type],
|
||||
metadata: {
|
||||
durationSeconds: action.metadata.duration_seconds ?? null,
|
||||
channelId: action.metadata.channel_id ?? null,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
if ('enabled' in data) {
|
||||
/**
|
||||
* Whether this auto moderation rule is enabled.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.enabled = data.enabled;
|
||||
}
|
||||
|
||||
if ('exempt_roles' in data) {
|
||||
/**
|
||||
* The roles exempt by this auto moderation rule.
|
||||
* @type {Collection<Snowflake, Role>}
|
||||
*/
|
||||
this.exemptRoles = new Collection(
|
||||
data.exempt_roles.map(exemptRole => [exemptRole, this.guild.roles.cache.get(exemptRole)]),
|
||||
);
|
||||
}
|
||||
|
||||
if ('exempt_channels' in data) {
|
||||
/**
|
||||
* The channels exempt by this auto moderation rule.
|
||||
* @type {Collection<Snowflake, GuildChannel|ThreadChannel>}
|
||||
*/
|
||||
this.exemptChannels = new Collection(
|
||||
data.exempt_channels.map(exemptChannel => [exemptChannel, this.guild.channels.cache.get(exemptChannel)]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits this auto moderation rule.
|
||||
* @param {AutoModerationRuleEditOptions} options Options for editing this auto moderation rule
|
||||
* @returns {Promise<AutoModerationRule>}
|
||||
*/
|
||||
edit(options) {
|
||||
return this.guild.autoModerationRules.edit(this.id, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes this auto moderation rule.
|
||||
* @param {string} [reason] The reason for deleting this auto moderation rule
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
delete(reason) {
|
||||
return this.guild.autoModerationRules.delete(this.id, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name for this auto moderation rule.
|
||||
* @param {string} name The name of this auto moderation rule
|
||||
* @param {string} [reason] The reason for changing the name of this auto moderation rule
|
||||
* @returns {Promise<AutoModerationRule>}
|
||||
*/
|
||||
setName(name, reason) {
|
||||
return this.edit({ name, reason });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the event type for this auto moderation rule.
|
||||
* @param {AutoModerationRuleEventType} eventType The event type of this auto moderation rule
|
||||
* @param {string} [reason] The reason for changing the event type of this auto moderation rule
|
||||
* @returns {Promise<AutoModerationRule>}
|
||||
*/
|
||||
setEventType(eventType, reason) {
|
||||
return this.edit({ eventType, reason });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the keyword filter for this auto moderation rule.
|
||||
* @param {string[]} keywordFilter The keyword filter of this auto moderation rule
|
||||
* @param {string} [reason] The reason for changing the keyword filter of this auto moderation rule
|
||||
* @returns {Promise<AutoModerationRule>}
|
||||
*/
|
||||
setKeywordFilter(keywordFilter, reason) {
|
||||
return this.edit({ triggerMetadata: { ...this.triggerMetadata, keywordFilter }, reason });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the regular expression patterns for this auto moderation rule.
|
||||
* @param {string[]} regexPatterns The regular expression patterns of this auto moderation rule
|
||||
* <info>Only Rust-flavored regular expressions are supported.</info>
|
||||
* @param {string} [reason] The reason for changing the regular expression patterns of this auto moderation rule
|
||||
* @returns {Promise<AutoModerationRule>}
|
||||
*/
|
||||
setRegexPatterns(regexPatterns, reason) {
|
||||
return this.edit({ triggerMetadata: { ...this.triggerMetadata, regexPatterns }, reason });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the presets for this auto moderation rule.
|
||||
* @param {AutoModerationRuleKeywordPresetType[]} presets The presets of this auto moderation rule
|
||||
* @param {string} [reason] The reason for changing the presets of this auto moderation rule
|
||||
* @returns {Promise<AutoModerationRule>}
|
||||
*/
|
||||
setPresets(presets, reason) {
|
||||
return this.edit({ triggerMetadata: { ...this.triggerMetadata, presets }, reason });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the allow list for this auto moderation rule.
|
||||
* @param {string[]} allowList The allow list of this auto moderation rule
|
||||
* @param {string} [reason] The reason for changing the allow list of this auto moderation rule
|
||||
* @returns {Promise<AutoModerationRule>}
|
||||
*/
|
||||
setAllowList(allowList, reason) {
|
||||
return this.edit({ triggerMetadata: { ...this.triggerMetadata, allowList }, reason });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the mention total limit for this auto moderation rule.
|
||||
* @param {number} mentionTotalLimit The mention total limit of this auto moderation rule
|
||||
* @param {string} [reason] The reason for changing the mention total limit of this auto moderation rule
|
||||
* @returns {Promise<AutoModerationRule>}
|
||||
*/
|
||||
setMentionTotalLimit(mentionTotalLimit, reason) {
|
||||
return this.edit({ triggerMetadata: { ...this.triggerMetadata, mentionTotalLimit }, reason });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the actions for this auto moderation rule.
|
||||
* @param {AutoModerationActionOptions[]} actions The actions of this auto moderation rule
|
||||
* @param {string} [reason] The reason for changing the actions of this auto moderation rule
|
||||
* @returns {Promise<AutoModerationRule>}
|
||||
*/
|
||||
setActions(actions, reason) {
|
||||
return this.edit({ actions, reason });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this auto moderation rule should be enabled.
|
||||
* @param {boolean} [enabled=true] Whether to enable this auto moderation rule
|
||||
* @param {string} [reason] The reason for enabling or disabling this auto moderation rule
|
||||
* @returns {Promise<AutoModerationRule>}
|
||||
*/
|
||||
setEnabled(enabled = true, reason) {
|
||||
return this.edit({ enabled, reason });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the exempt roles for this auto moderation rule.
|
||||
* @param {Collection<Snowflake, Role>|RoleResolvable[]} [exemptRoles] The exempt roles of this auto moderation rule
|
||||
* @param {string} [reason] The reason for changing the exempt roles of this auto moderation rule
|
||||
* @returns {Promise<AutoModerationRule>}
|
||||
*/
|
||||
setExemptRoles(exemptRoles, reason) {
|
||||
return this.edit({ exemptRoles, reason });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the exempt channels for this auto moderation rule.
|
||||
* @param {Collection<Snowflake, GuildChannel|ThreadChannel>|GuildChannelResolvable[]} [exemptChannels]
|
||||
* The exempt channels of this auto moderation rule
|
||||
* @param {string} [reason] The reason for changing the exempt channels of this auto moderation rule
|
||||
* @returns {Promise<AutoModerationRule>}
|
||||
*/
|
||||
setExemptChannels(exemptChannels, reason) {
|
||||
return this.edit({ exemptChannels, reason });
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AutoModerationRule;
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
const CommandInteractionOptionResolver = require('./CommandInteractionOptionResolver');
|
||||
const Interaction = require('./Interaction');
|
||||
const { Error } = require('../errors');
|
||||
const { InteractionResponseTypes, ApplicationCommandOptionTypes } = require('../util/Constants');
|
||||
|
||||
/**
|
||||
@@ -76,7 +77,7 @@ class AutocompleteInteraction extends 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>}
|
||||
* @example
|
||||
* // respond to autocomplete interaction
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const Interaction = require('./Interaction');
|
||||
const InteractionWebhook = require('./InteractionWebhook');
|
||||
const MessageAttachment = require('./MessageAttachment');
|
||||
const InteractionResponses = require('./interfaces/InteractionResponses');
|
||||
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, Channel|APIChannel>} [channels] The resolved channels
|
||||
* @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}
|
||||
* @private
|
||||
*/
|
||||
transformResolved({ members, users, channels, roles, messages }) {
|
||||
transformResolved({ members, users, channels, roles, messages, attachments }) {
|
||||
const result = {};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -139,6 +149,7 @@ class BaseCommandInteraction extends Interaction {
|
||||
* @property {GuildMember|APIGuildMember} [member] The resolved member
|
||||
* @property {GuildChannel|ThreadChannel|APIChannel} [channel] The resolved channel
|
||||
* @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];
|
||||
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;
|
||||
@@ -182,6 +196,8 @@ class BaseCommandInteraction extends Interaction {
|
||||
editReply() {}
|
||||
deleteReply() {}
|
||||
followUp() {}
|
||||
showModal() {}
|
||||
awaitModalSubmit() {}
|
||||
}
|
||||
|
||||
InteractionResponses.applyToClass(BaseCommandInteraction, ['deferUpdate', 'update']);
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const GuildChannel = require('./GuildChannel');
|
||||
const Webhook = require('./Webhook');
|
||||
const TextBasedChannel = require('./interfaces/TextBasedChannel');
|
||||
const GuildTextThreadManager = require('../managers/GuildTextThreadManager');
|
||||
const MessageManager = require('../managers/MessageManager');
|
||||
const ThreadManager = require('../managers/ThreadManager');
|
||||
const DataResolver = require('../util/DataResolver');
|
||||
|
||||
/**
|
||||
* Represents a text-based guild channel on Discord.
|
||||
@@ -25,9 +22,9 @@ class BaseGuildTextChannel extends GuildChannel {
|
||||
|
||||
/**
|
||||
* A manager of the threads belonging to this channel
|
||||
* @type {ThreadManager}
|
||||
* @type {GuildTextThreadManager}
|
||||
*/
|
||||
this.threads = new ThreadManager(this);
|
||||
this.threads = new GuildTextThreadManager(this);
|
||||
|
||||
/**
|
||||
* If the guild considers this channel NSFW
|
||||
@@ -72,7 +69,7 @@ class BaseGuildTextChannel extends GuildChannel {
|
||||
if ('default_auto_archive_duration' in data) {
|
||||
/**
|
||||
* The default auto archive duration for newly created threads in this channel
|
||||
* @type {?ThreadAutoArchiveDuration}
|
||||
* @type {?number}
|
||||
*/
|
||||
this.defaultAutoArchiveDuration = data.default_auto_archive_duration;
|
||||
}
|
||||
@@ -92,16 +89,6 @@ class BaseGuildTextChannel extends GuildChannel {
|
||||
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)
|
||||
* @param {string} type The new channel type
|
||||
@@ -112,57 +99,6 @@ class BaseGuildTextChannel extends GuildChannel {
|
||||
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.
|
||||
* @param {?string} topic The new topic for the guild channel
|
||||
@@ -178,6 +114,14 @@ class BaseGuildTextChannel extends GuildChannel {
|
||||
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.
|
||||
* @typedef {Object} CreateInviteOptions
|
||||
@@ -229,6 +173,10 @@ class BaseGuildTextChannel extends GuildChannel {
|
||||
createMessageComponentCollector() {}
|
||||
awaitMessageComponent() {}
|
||||
bulkDelete() {}
|
||||
fetchWebhooks() {}
|
||||
createWebhook() {}
|
||||
setRateLimitPerUser() {}
|
||||
setNSFW() {}
|
||||
}
|
||||
|
||||
TextBasedChannel.applyToClass(BaseGuildTextChannel, true);
|
||||
|
||||
@@ -75,24 +75,25 @@ class BaseGuildVoiceChannel extends GuildChannel {
|
||||
if (permissions.has(Permissions.FLAGS.ADMINISTRATOR, false)) return true;
|
||||
|
||||
return (
|
||||
this.guild.me.communicationDisabledUntilTimestamp < Date.now() &&
|
||||
this.guild.members.me.communicationDisabledUntilTimestamp < Date.now() &&
|
||||
permissions.has(Permissions.FLAGS.CONNECT, false)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>}
|
||||
* @example
|
||||
* // Set the RTC region to europe
|
||||
* channel.setRTCRegion('europe');
|
||||
* // Set the RTC region to sydney
|
||||
* channel.setRTCRegion('sydney');
|
||||
* @example
|
||||
* // 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) {
|
||||
return this.edit({ rtcRegion: region });
|
||||
setRTCRegion(rtcRegion, reason) {
|
||||
return this.edit({ rtcRegion }, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@ const { TypeError } = require('../errors');
|
||||
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}
|
||||
*/
|
||||
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
|
||||
* * MessageButtonOptions
|
||||
* * MessageSelectMenuOptions
|
||||
* * TextInputComponentOptions
|
||||
* @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
|
||||
* * MessageButton
|
||||
* * MessageSelectMenu
|
||||
* * TextInputComponent
|
||||
* @typedef {MessageActionRow|MessageButton|MessageSelectMenu} MessageComponent
|
||||
* @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 {Client|WebhookClient} [client] Client constructing this component
|
||||
* @returns {?MessageComponent}
|
||||
* @returns {?(MessageComponent|ModalComponent)}
|
||||
* @private
|
||||
*/
|
||||
static create(data, client) {
|
||||
@@ -79,6 +81,11 @@ class BaseMessageComponent {
|
||||
component = data instanceof MessageSelectMenu ? data : new MessageSelectMenu(data);
|
||||
break;
|
||||
}
|
||||
case MessageComponentTypes.TEXT_INPUT: {
|
||||
const TextInputComponent = require('./TextInputComponent');
|
||||
component = data instanceof TextInputComponent ? data : new TextInputComponent(data);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (client) {
|
||||
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
|
||||
* @returns {MessageComponentType}
|
||||
* @private
|
||||
|
||||
@@ -30,16 +30,25 @@ class CategoryChannel extends GuildChannel {
|
||||
/**
|
||||
* Options for creating a channel using {@link CategoryChannel#createChannel}.
|
||||
* @typedef {Object} CategoryCreateChannelOptions
|
||||
* @property {string} [name] The name of the new channel
|
||||
* @property {ChannelType|number} [type='GUILD_TEXT'] The type of the new channel.
|
||||
* @property {number} [position] Position of the new channel
|
||||
* @property {string} [topic] The topic for the new channel
|
||||
* @property {boolean} [nsfw] Whether the new channel is NSFW
|
||||
* @property {number} [bitrate] Bitrate of the new channel in bits (only voice)
|
||||
* @property {number} [userLimit] Maximum amount of users allowed in the new channel (only voice)
|
||||
* @property {OverwriteResolvable[]|Collection<Snowflake, OverwriteResolvable>} [permissionOverwrites]
|
||||
* Permission overwrites of the new channel
|
||||
* @property {number} [position] Position of the new channel
|
||||
* @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the new channel in seconds
|
||||
* @property {string} [rtcRegion] The specific region of the new channel.
|
||||
* @property {ThreadAutoArchiveDuration} [defaultAutoArchiveDuration]
|
||||
* The default auto archive duration for all new threads in this channel
|
||||
* @property {?string} [rtcRegion] The specific region of the new channel
|
||||
* @property {?VideoQualityMode|number} [videoQualityMode] The camera video quality mode of the new channel
|
||||
* @property {ChannelFlagsResolvable} [flags] The flags to set on the new channel
|
||||
* @property {GuildForumTagData[]} [availableTags] The tags to set as available in a forum channel
|
||||
* @property {?DefaultReactionEmoji} [defaultReactionEmoji] The emoji to set as the default reaction emoji
|
||||
* @property {number} [defaultThreadRateLimitPerUser] The rate limit per user (slowmode) to set on forum posts
|
||||
* @property {?SortOrderType} [defaultSortOrder] The default sort order mode to set on the new channel
|
||||
* @property {string} [reason] Reason for creating the new channel
|
||||
*/
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@ let StoreChannel;
|
||||
let TextChannel;
|
||||
let ThreadChannel;
|
||||
let VoiceChannel;
|
||||
let DirectoryChannel;
|
||||
let ForumChannel;
|
||||
const ChannelFlags = require('../util/ChannelFlags');
|
||||
const { ChannelTypes, ThreadChannelTypes, VoiceBasedChannelTypes } = require('../util/Constants');
|
||||
const SnowflakeUtil = require('../util/SnowflakeUtil');
|
||||
|
||||
@@ -46,6 +49,17 @@ class Channel extends Base {
|
||||
* @type {Snowflake}
|
||||
*/
|
||||
this.id = data.id;
|
||||
|
||||
if ('flags' in data) {
|
||||
/**
|
||||
* The flags that are applied to the channel.
|
||||
* <info>This is only `null` in a {@link PartialGroupDMChannel}. In all other cases, it is not `null`.</info>
|
||||
* @type {?Readonly<ChannelFlags>}
|
||||
*/
|
||||
this.flags = new ChannelFlags(data.flags).freeze();
|
||||
} else {
|
||||
this.flags ??= new ChannelFlags().freeze();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,6 +178,14 @@ class Channel extends Base {
|
||||
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 } = {}) {
|
||||
CategoryChannel ??= require('./CategoryChannel');
|
||||
DMChannel ??= require('./DMChannel');
|
||||
@@ -173,6 +195,8 @@ class Channel extends Base {
|
||||
TextChannel ??= require('./TextChannel');
|
||||
ThreadChannel ??= require('./ThreadChannel');
|
||||
VoiceChannel ??= require('./VoiceChannel');
|
||||
DirectoryChannel ??= require('./DirectoryChannel');
|
||||
ForumChannel ??= require('./ForumChannel');
|
||||
|
||||
let channel;
|
||||
if (!data.guild_id && !guild) {
|
||||
@@ -218,6 +242,14 @@ class Channel extends Base {
|
||||
if (!allowUnknownGuild) channel.parent?.threads.cache.set(channel.id, channel);
|
||||
break;
|
||||
}
|
||||
|
||||
case ChannelTypes.GUILD_DIRECTORY:
|
||||
channel = new DirectoryChannel(client, data);
|
||||
break;
|
||||
|
||||
case ChannelTypes.GUILD_FORUM:
|
||||
channel = new ForumChannel(guild, data, client);
|
||||
break;
|
||||
}
|
||||
if (channel && !allowUnknownGuild) guild.channels?.cache.set(channel.id, channel);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
const { ApplicationRoleConnectionMetadata } = require('./ApplicationRoleConnectionMetadata');
|
||||
const Team = require('./Team');
|
||||
const Application = require('./interfaces/Application');
|
||||
const ApplicationCommandManager = require('../managers/ApplicationCommandManager');
|
||||
const ApplicationFlags = require('../util/ApplicationFlags');
|
||||
const { ApplicationRoleConnectionMetadataTypes } = require('../util/Constants');
|
||||
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.
|
||||
@@ -23,6 +32,35 @@ class ClientApplication extends Application {
|
||||
_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) {
|
||||
/**
|
||||
* The flags this application has
|
||||
@@ -100,6 +138,48 @@ class ClientApplication extends Application {
|
||||
this._patch(app);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this application's role connection metadata records
|
||||
* @returns {Promise<ApplicationRoleConnectionMetadata[]>}
|
||||
*/
|
||||
async fetchRoleConnectionMetadataRecords() {
|
||||
const metadata = await this.client.api.applications(this.client.user.id)('role-connections').metadata.get();
|
||||
return metadata.map(data => new ApplicationRoleConnectionMetadata(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data for creating or editing an application role connection metadata.
|
||||
* @typedef {Object} ApplicationRoleConnectionMetadataEditOptions
|
||||
* @property {string} name The name of the metadata field
|
||||
* @property {?Object<Locale, string>} [nameLocalizations] The name localizations for the metadata field
|
||||
* @property {string} description The description of the metadata field
|
||||
* @property {?Object<Locale, string>} [descriptionLocalizations] The description localizations for the metadata field
|
||||
* @property {string} key The dictionary key of the metadata field
|
||||
* @property {ApplicationRoleConnectionMetadataType} type The type of the metadata field
|
||||
*/
|
||||
|
||||
/**
|
||||
* Updates this application's role connection metadata records
|
||||
* @param {ApplicationRoleConnectionMetadataEditOptions[]} records The new role connection metadata records
|
||||
* @returns {Promise<ApplicationRoleConnectionMetadata[]>}
|
||||
*/
|
||||
async editRoleConnectionMetadataRecords(records) {
|
||||
const newRecords = await this.client.api
|
||||
.applications(this.client.user.id)('role-connections')
|
||||
.metadata.put({
|
||||
data: records.map(record => ({
|
||||
type: typeof record.type === 'string' ? ApplicationRoleConnectionMetadataTypes[record.type] : record.type,
|
||||
key: record.key,
|
||||
name: record.name,
|
||||
name_localizations: record.nameLocalizations,
|
||||
description: record.description,
|
||||
description_localizations: record.descriptionLocalizations,
|
||||
})),
|
||||
});
|
||||
|
||||
return newRecords.map(data => new ApplicationRoleConnectionMetadata(data));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ClientApplication;
|
||||
|
||||
@@ -240,10 +240,19 @@ class CommandInteractionOptionResolver {
|
||||
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.
|
||||
* @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
|
||||
*/
|
||||
getFocused(getFull = false) {
|
||||
@@ -251,6 +260,17 @@ class CommandInteractionOptionResolver {
|
||||
if (!focusedOption) throw new TypeError('AUTOCOMPLETE_INTERACTION_OPTION_NO_FOCUSED_OPTION');
|
||||
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;
|
||||
|
||||
@@ -22,7 +22,7 @@ class ContextMenuInteraction extends BaseCommandInteraction {
|
||||
);
|
||||
|
||||
/**
|
||||
* The id of the target of the interaction
|
||||
* The id of the target of this interaction
|
||||
* @type {Snowflake}
|
||||
*/
|
||||
this.targetId = data.data.target_id;
|
||||
|
||||
@@ -94,8 +94,16 @@ class DMChannel extends Channel {
|
||||
createMessageComponentCollector() {}
|
||||
awaitMessageComponent() {}
|
||||
// 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;
|
||||
|
||||
20
src/structures/DirectoryChannel.js
Normal file
20
src/structures/DirectoryChannel.js
Normal file
@@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
const { Channel } = require('./Channel');
|
||||
|
||||
/**
|
||||
* Represents a channel that displays a directory of guilds.
|
||||
* @extends {Channel}
|
||||
*/
|
||||
class DirectoryChannel extends Channel {
|
||||
_patch(data) {
|
||||
super._patch(data);
|
||||
/**
|
||||
* The channel's name
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = data.name;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DirectoryChannel;
|
||||
264
src/structures/ForumChannel.js
Normal file
264
src/structures/ForumChannel.js
Normal file
@@ -0,0 +1,264 @@
|
||||
'use strict';
|
||||
|
||||
const GuildChannel = require('./GuildChannel');
|
||||
const TextBasedChannel = require('./interfaces/TextBasedChannel');
|
||||
const GuildForumThreadManager = require('../managers/GuildForumThreadManager');
|
||||
const { SortOrderTypes, ForumLayoutTypes } = require('../util/Constants');
|
||||
const { transformAPIGuildForumTag, transformAPIGuildDefaultReaction } = require('../util/Util');
|
||||
|
||||
/**
|
||||
* @typedef {Object} GuildForumTagEmoji
|
||||
* @property {?Snowflake} id The id of a guild's custom emoji
|
||||
* @property {?string} name The unicode character of the emoji
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} GuildForumTag
|
||||
* @property {Snowflake} id The id of the tag
|
||||
* @property {string} name The name of the tag
|
||||
* @property {boolean} moderated Whether this tag can only be added to or removed from threads
|
||||
* by a member with the `ManageThreads` permission
|
||||
* @property {?GuildForumTagEmoji} emoji The emoji of this tag
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} GuildForumTagData
|
||||
* @property {Snowflake} [id] The id of the tag
|
||||
* @property {string} name The name of the tag
|
||||
* @property {boolean} [moderated] Whether this tag can only be added to or removed from threads
|
||||
* by a member with the `ManageThreads` permission
|
||||
* @property {?GuildForumTagEmoji} [emoji] The emoji of this tag
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} DefaultReactionEmoji
|
||||
* @property {?Snowflake} id The id of a guild's custom emoji
|
||||
* @property {?string} name The unicode character of the emoji
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a channel that only contains threads
|
||||
* @extends {GuildChannel}
|
||||
* @implements {TextBasedChannel}
|
||||
*/
|
||||
class ForumChannel extends GuildChannel {
|
||||
constructor(guild, data, client) {
|
||||
super(guild, data, client, false);
|
||||
|
||||
/**
|
||||
* A manager of the threads belonging to this channel
|
||||
* @type {GuildForumThreadManager}
|
||||
*/
|
||||
this.threads = new GuildForumThreadManager(this);
|
||||
|
||||
this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
super._patch(data);
|
||||
if ('available_tags' in data) {
|
||||
/**
|
||||
* The set of tags that can be used in this channel.
|
||||
* @type {GuildForumTag[]}
|
||||
*/
|
||||
this.availableTags = data.available_tags.map(tag => transformAPIGuildForumTag(tag));
|
||||
} else {
|
||||
this.availableTags ??= [];
|
||||
}
|
||||
|
||||
if ('default_reaction_emoji' in data) {
|
||||
/**
|
||||
* The emoji to show in the add reaction button on a thread in a guild forum channel
|
||||
* @type {?DefaultReactionEmoji}
|
||||
*/
|
||||
this.defaultReactionEmoji =
|
||||
data.default_reaction_emoji && transformAPIGuildDefaultReaction(data.default_reaction_emoji);
|
||||
} else {
|
||||
this.defaultReactionEmoji ??= null;
|
||||
}
|
||||
|
||||
if ('default_thread_rate_limit_per_user' in data) {
|
||||
/**
|
||||
* The initial rate limit per user (slowmode) to set on newly created threads in a channel.
|
||||
* @type {?number}
|
||||
*/
|
||||
this.defaultThreadRateLimitPerUser = data.default_thread_rate_limit_per_user;
|
||||
} else {
|
||||
this.defaultThreadRateLimitPerUser ??= null;
|
||||
}
|
||||
|
||||
if ('rate_limit_per_user' in data) {
|
||||
/**
|
||||
* The rate limit per user (slowmode) for this channel.
|
||||
* @type {?number}
|
||||
*/
|
||||
this.rateLimitPerUser = data.rate_limit_per_user;
|
||||
} else {
|
||||
this.rateLimitPerUser ??= null;
|
||||
}
|
||||
|
||||
if ('default_auto_archive_duration' in data) {
|
||||
/**
|
||||
* The default auto archive duration for newly created threads in this channel.
|
||||
* @type {?ThreadAutoArchiveDuration}
|
||||
*/
|
||||
this.defaultAutoArchiveDuration = data.default_auto_archive_duration;
|
||||
} else {
|
||||
this.defaultAutoArchiveDuration ??= null;
|
||||
}
|
||||
|
||||
if ('nsfw' in data) {
|
||||
/**
|
||||
* If this channel is considered NSFW.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.nsfw = data.nsfw;
|
||||
} else {
|
||||
this.nsfw ??= false;
|
||||
}
|
||||
|
||||
if ('topic' in data) {
|
||||
/**
|
||||
* The topic of this channel.
|
||||
* @type {?string}
|
||||
*/
|
||||
this.topic = data.topic;
|
||||
}
|
||||
|
||||
if ('default_sort_order' in data) {
|
||||
/**
|
||||
* The default sort order mode used to order posts
|
||||
* @type {?SortOrderType}
|
||||
*/
|
||||
this.defaultSortOrder = SortOrderTypes[data.default_sort_order];
|
||||
} else {
|
||||
this.defaultSortOrder ??= null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default layout type used to display posts
|
||||
* @type {ForumLayoutType}
|
||||
*/
|
||||
this.defaultForumLayout = ForumLayoutTypes[data.default_forum_layout];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the available tags for this forum channel
|
||||
* @param {GuildForumTagData[]} availableTags The tags to set as available in this channel
|
||||
* @param {string} [reason] Reason for changing the available tags
|
||||
* @returns {Promise<ForumChannel>}
|
||||
*/
|
||||
setAvailableTags(availableTags, reason) {
|
||||
return this.edit({ availableTags }, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default reaction emoji for this channel
|
||||
* @param {?DefaultReactionEmoji} defaultReactionEmoji The emoji to set as the default reaction emoji
|
||||
* @param {string} [reason] Reason for changing the default reaction emoji
|
||||
* @returns {Promise<ForumChannel>}
|
||||
*/
|
||||
setDefaultReactionEmoji(defaultReactionEmoji, reason) {
|
||||
return this.edit({ defaultReactionEmoji }, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default rate limit per user (slowmode) for new threads in this channel
|
||||
* @param {number} defaultThreadRateLimitPerUser The rate limit to set on newly created threads in this channel
|
||||
* @param {string} [reason] Reason for changing the default rate limit
|
||||
* @returns {Promise<ForumChannel>}
|
||||
*/
|
||||
setDefaultThreadRateLimitPerUser(defaultThreadRateLimitPerUser, reason) {
|
||||
return this.edit({ defaultThreadRateLimitPerUser }, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default sort order mode used to order posts
|
||||
* @param {?SortOrderType} defaultSortOrder The default sort order mode to set on this channel
|
||||
* @param {string} [reason] Reason for changing the default sort order
|
||||
* @returns {Promise<ForumChannel>}
|
||||
*/
|
||||
setDefaultSortOrder(defaultSortOrder, reason) {
|
||||
return this.edit({ defaultSortOrder }, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default forum layout type used to display posts
|
||||
* @param {ForumLayoutType} defaultForumLayout The default forum layout type to set on this channel
|
||||
* @param {string} [reason] Reason for changing the default forum layout
|
||||
* @returns {Promise<ForumChannel>}
|
||||
*/
|
||||
setDefaultForumLayout(defaultForumLayout, reason) {
|
||||
return this.edit({ defaultForumLayout }, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an invite to this guild channel.
|
||||
* @param {CreateInviteOptions} [options={}] The options for creating the invite
|
||||
* @returns {Promise<Invite>}
|
||||
* @example
|
||||
* // Create an invite to a channel
|
||||
* channel.createInvite()
|
||||
* .then(invite => console.log(`Created an invite with a code of ${invite.code}`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
createInvite(options) {
|
||||
return this.guild.invites.create(this.id, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a collection of invites to this guild channel.
|
||||
* Resolves with a collection mapping invites by their codes.
|
||||
* @param {boolean} [cache=true] Whether or not to cache the fetched invites
|
||||
* @returns {Promise<Collection<string, Invite>>}
|
||||
*/
|
||||
fetchInvites(cache = true) {
|
||||
return this.guild.invites.fetch({ channelId: this.id, cache });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default auto archive duration for all newly created threads in this channel.
|
||||
* @param {ThreadAutoArchiveDuration} defaultAutoArchiveDuration The new default auto archive duration
|
||||
* @param {string} [reason] Reason for changing the channel's default auto archive duration
|
||||
* @returns {Promise<ForumChannel>}
|
||||
*/
|
||||
setDefaultAutoArchiveDuration(defaultAutoArchiveDuration, reason) {
|
||||
return this.edit({ defaultAutoArchiveDuration }, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new topic for the guild channel.
|
||||
* @param {?string} topic The new topic for the guild channel
|
||||
* @param {string} [reason] Reason for changing the guild channel's topic
|
||||
* @returns {Promise<ForumChannel>}
|
||||
* @example
|
||||
* // Set a new channel topic
|
||||
* channel.setTopic('needs more rate limiting')
|
||||
* .then(newChannel => console.log(`Channel's new topic is ${newChannel.topic}`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
setTopic(topic, reason) {
|
||||
return this.edit({ topic }, reason);
|
||||
}
|
||||
|
||||
// These are here only for documentation purposes - they are implemented by TextBasedChannel
|
||||
/* eslint-disable no-empty-function */
|
||||
createWebhook() {}
|
||||
fetchWebhooks() {}
|
||||
setNSFW() {}
|
||||
setRateLimitPerUser() {}
|
||||
}
|
||||
|
||||
TextBasedChannel.applyToClass(ForumChannel, true, [
|
||||
'send',
|
||||
'lastMessage',
|
||||
'lastPinAt',
|
||||
'bulkDelete',
|
||||
'sendTyping',
|
||||
'createMessageCollector',
|
||||
'awaitMessages',
|
||||
'createMessageComponentCollector',
|
||||
'awaitMessageComponent',
|
||||
]);
|
||||
|
||||
module.exports = ForumChannel;
|
||||
@@ -10,6 +10,7 @@ const Integration = require('./Integration');
|
||||
const Webhook = require('./Webhook');
|
||||
const WelcomeScreen = require('./WelcomeScreen');
|
||||
const { Error } = require('../errors');
|
||||
const AutoModerationRuleManager = require('../managers/AutoModerationRuleManager');
|
||||
const GuildApplicationCommandManager = require('../managers/GuildApplicationCommandManager');
|
||||
const GuildBanManager = require('../managers/GuildBanManager');
|
||||
const GuildChannelManager = require('../managers/GuildChannelManager');
|
||||
@@ -25,7 +26,6 @@ const VoiceStateManager = require('../managers/VoiceStateManager');
|
||||
const {
|
||||
ChannelTypes,
|
||||
DefaultMessageNotificationLevels,
|
||||
PartialTypes,
|
||||
VerificationLevels,
|
||||
ExplicitContentFilterLevels,
|
||||
Status,
|
||||
@@ -39,6 +39,7 @@ const Util = require('../util/Util');
|
||||
let deprecationEmittedForSetChannelPositions = false;
|
||||
let deprecationEmittedForSetRolePositions = false;
|
||||
let deprecationEmittedForDeleted = false;
|
||||
let deprecationEmittedForMe = false;
|
||||
|
||||
/**
|
||||
* @type {WeakSet<Guild>}
|
||||
@@ -117,6 +118,12 @@ class Guild extends AnonymousGuild {
|
||||
*/
|
||||
this.scheduledEvents = new GuildScheduledEventManager(this);
|
||||
|
||||
/**
|
||||
* A manager of the auto moderation rules of this guild.
|
||||
* @type {AutoModerationRuleManager}
|
||||
*/
|
||||
this.autoModerationRules = new AutoModerationRuleManager(this);
|
||||
|
||||
if (!data) return;
|
||||
if (data.unavailable) {
|
||||
/**
|
||||
@@ -221,11 +228,15 @@ class Guild extends AnonymousGuild {
|
||||
/**
|
||||
* An array of enabled guild features, here are the possible values:
|
||||
* * ANIMATED_ICON
|
||||
* * AUTO_MODERATION
|
||||
* * BANNER
|
||||
* * COMMERCE
|
||||
* * COMMUNITY
|
||||
* * CREATOR_MONETIZABLE_PROVISIONAL
|
||||
* * CREATOR_STORE_PAGE
|
||||
* * DISCOVERABLE
|
||||
* * FEATURABLE
|
||||
* * INVITES_DISABLED
|
||||
* * INVITE_SPLASH
|
||||
* * MEMBER_VERIFICATION_GATE_ENABLED
|
||||
* * NEWS
|
||||
@@ -237,11 +248,15 @@ class Guild extends AnonymousGuild {
|
||||
* * WELCOME_SCREEN_ENABLED
|
||||
* * TICKETED_EVENTS_ENABLED
|
||||
* * MONETIZATION_ENABLED
|
||||
* <warn>`MONETIZATION_ENABLED` has been replaced.
|
||||
* See [this pull request](https://github.com/discord/discord-api-docs/pull/5724) for more information.</warn>
|
||||
* * MORE_STICKERS
|
||||
* * THREE_DAY_THREAD_ARCHIVE
|
||||
* * SEVEN_DAY_THREAD_ARCHIVE
|
||||
* * PRIVATE_THREADS
|
||||
* * ROLE_ICONS
|
||||
* * ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE
|
||||
* * ROLE_SUBSCRIPTIONS_ENABLED
|
||||
* @typedef {string} Features
|
||||
* @see {@link https://discord.com/developers/docs/resources/guild#guild-object-guild-features}
|
||||
*/
|
||||
@@ -286,14 +301,6 @@ class Guild extends AnonymousGuild {
|
||||
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) {
|
||||
/**
|
||||
* Whether widget images are enabled on this guild
|
||||
@@ -371,6 +378,16 @@ class Guild extends AnonymousGuild {
|
||||
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) {
|
||||
/**
|
||||
* The approximate amount of members the guild has
|
||||
@@ -419,8 +436,8 @@ class Guild extends AnonymousGuild {
|
||||
if ('preferred_locale' in data) {
|
||||
/**
|
||||
* The preferred locale of the guild, defaults to `en-US`
|
||||
* @type {string}
|
||||
* @see {@link https://discord.com/developers/docs/dispatch/field-values#predefined-field-values-accepted-locales}
|
||||
* @type {Locale}
|
||||
* @see {@link https://discord.com/developers/docs/reference#locales}
|
||||
*/
|
||||
this.preferredLocale = data.preferred_locale;
|
||||
}
|
||||
@@ -560,7 +577,7 @@ class Guild extends AnonymousGuild {
|
||||
|
||||
/**
|
||||
* Widget channel for this guild
|
||||
* @type {?TextChannel}
|
||||
* @type {?(TextChannel|NewsChannel|VoiceChannel|StageChannel|ForumChannel)}
|
||||
* @readonly
|
||||
*/
|
||||
get widgetChannel() {
|
||||
@@ -588,15 +605,16 @@ class Guild extends AnonymousGuild {
|
||||
/**
|
||||
* The client user as a GuildMember of this guild
|
||||
* @type {?GuildMember}
|
||||
* @deprecated Use {@link GuildMemberManager#me} instead.
|
||||
* @readonly
|
||||
*/
|
||||
get me() {
|
||||
return (
|
||||
this.members.resolve(this.client.user.id) ??
|
||||
(this.client.options.partials.includes(PartialTypes.GUILD_MEMBER)
|
||||
? this.members._add({ user: { id: this.client.user.id } }, true)
|
||||
: null)
|
||||
);
|
||||
if (!deprecationEmittedForMe) {
|
||||
process.emitWarning('Guild#me is deprecated. Use Guild#members#me instead.', 'DeprecationWarning');
|
||||
deprecationEmittedForMe = true;
|
||||
}
|
||||
|
||||
return this.members.me;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -773,7 +791,8 @@ class Guild extends AnonymousGuild {
|
||||
/**
|
||||
* Options used to fetch audit logs.
|
||||
* @typedef {Object} GuildAuditLogsFetchOptions
|
||||
* @property {Snowflake|GuildAuditLogsEntry} [before] Only return entries before this entry
|
||||
* @property {Snowflake|GuildAuditLogsEntry} [before] Consider only entries before this entry
|
||||
* @property {Snowflake|GuildAuditLogsEntry} [after] Consider only entries after this entry
|
||||
* @property {number} [limit] The number of entries to return
|
||||
* @property {UserResolvable} [user] Only return entries for actions made by this user
|
||||
* @property {AuditLogAction|number} [type] Only return entries for this action type
|
||||
@@ -789,18 +808,17 @@ class Guild extends AnonymousGuild {
|
||||
* .then(audit => console.log(audit.entries.first()))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async fetchAuditLogs(options = {}) {
|
||||
if (options.before && options.before instanceof GuildAuditLogs.Entry) options.before = options.before.id;
|
||||
if (typeof options.type === 'string') options.type = GuildAuditLogs.Actions[options.type];
|
||||
|
||||
async fetchAuditLogs({ before, after, limit, user, type } = {}) {
|
||||
const data = await this.client.api.guilds(this.id)['audit-logs'].get({
|
||||
query: {
|
||||
before: options.before,
|
||||
limit: options.limit,
|
||||
user_id: this.client.users.resolveId(options.user),
|
||||
action_type: options.type,
|
||||
before: before?.id ?? before,
|
||||
after: after?.id ?? after,
|
||||
limit,
|
||||
user_id: this.client.users.resolveId(user),
|
||||
action_type: typeof type === 'string' ? GuildAuditLogs.Actions[type] : type,
|
||||
},
|
||||
});
|
||||
|
||||
return GuildAuditLogs.build(this, data);
|
||||
}
|
||||
|
||||
@@ -808,24 +826,24 @@ class Guild extends AnonymousGuild {
|
||||
* The data for editing a guild.
|
||||
* @typedef {Object} GuildEditData
|
||||
* @property {string} [name] The name 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 {VoiceChannelResolvable} [afkChannel] The AFK channel of the guild
|
||||
* @property {TextChannelResolvable} [systemChannel] The system channel 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 {?VoiceChannelResolvable} [afkChannel] The AFK channel of the guild
|
||||
* @property {?TextChannelResolvable} [systemChannel] The system channel of the guild
|
||||
* @property {number} [afkTimeout] The AFK timeout of the guild
|
||||
* @property {?(BufferResolvable|Base64Resolvable)} [icon] The icon 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)} [discoverySplash] The discovery splash image of the guild
|
||||
* @property {?(BufferResolvable|Base64Resolvable)} [banner] The banner of the guild
|
||||
* @property {DefaultMessageNotificationLevel|number} [defaultMessageNotifications] The default message notification
|
||||
* level of the guild
|
||||
* @property {?(DefaultMessageNotificationLevel|number)} [defaultMessageNotifications] The default message
|
||||
* notification level of the guild
|
||||
* @property {SystemChannelFlagsResolvable} [systemChannelFlags] The system channel flags of the guild
|
||||
* @property {TextChannelResolvable} [rulesChannel] The rules channel of the guild
|
||||
* @property {TextChannelResolvable} [publicUpdatesChannel] The community updates channel of the guild
|
||||
* @property {string} [preferredLocale] The preferred locale of the guild
|
||||
* @property {?TextChannelResolvable} [rulesChannel] The rules channel of the guild
|
||||
* @property {?TextChannelResolvable} [publicUpdatesChannel] The community updates channel 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 {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
|
||||
*/
|
||||
|
||||
@@ -906,7 +924,7 @@ class Guild extends AnonymousGuild {
|
||||
if (typeof data.description !== 'undefined') {
|
||||
_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;
|
||||
const newData = await this.client.api.guilds(this.id).patch({ data: _data, reason });
|
||||
return this.client.actions.GuildUpdate.handle(newData).updated;
|
||||
@@ -984,7 +1002,7 @@ class Guild extends AnonymousGuild {
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @returns {Promise<Guild>}
|
||||
*/
|
||||
@@ -995,7 +1013,7 @@ class Guild extends AnonymousGuild {
|
||||
/* eslint-disable max-len */
|
||||
/**
|
||||
* 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
|
||||
* @returns {Promise<Guild>}
|
||||
*/
|
||||
@@ -1031,7 +1049,7 @@ class Guild extends AnonymousGuild {
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @returns {Promise<Guild>}
|
||||
* @example
|
||||
@@ -1046,7 +1064,7 @@ class Guild extends AnonymousGuild {
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @returns {Promise<Guild>}
|
||||
* @example
|
||||
@@ -1061,7 +1079,7 @@ class Guild extends AnonymousGuild {
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @returns {Promise<Guild>}
|
||||
* @example
|
||||
@@ -1166,7 +1184,7 @@ class Guild extends AnonymousGuild {
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @returns {Promise<Guild>}
|
||||
* @example
|
||||
@@ -1181,7 +1199,7 @@ class Guild extends AnonymousGuild {
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @returns {Promise<Guild>}
|
||||
* @example
|
||||
@@ -1196,7 +1214,7 @@ class Guild extends AnonymousGuild {
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @returns {Promise<Guild>}
|
||||
* @example
|
||||
@@ -1306,6 +1324,17 @@ class Guild extends AnonymousGuild {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this guild's invites are disabled.
|
||||
* @param {boolean} [disabled=true] Whether the invites are disabled
|
||||
* @returns {Promise<Guild>}
|
||||
*/
|
||||
disableInvites(disabled = true) {
|
||||
const features = this.features.filter(feature => feature !== 'INVITES_DISABLED');
|
||||
if (disabled) features.push('INVITES_DISABLED');
|
||||
return this.edit({ features });
|
||||
}
|
||||
|
||||
/**
|
||||
* Leaves the guild.
|
||||
* @returns {Promise<Guild>}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const ApplicationCommand = require('./ApplicationCommand');
|
||||
const AutoModerationRule = require('./AutoModerationRule');
|
||||
const { GuildScheduledEvent } = require('./GuildScheduledEvent');
|
||||
const Integration = require('./Integration');
|
||||
const Invite = require('./Invite');
|
||||
const { StageInstance } = require('./StageInstance');
|
||||
const { Sticker } = require('./Sticker');
|
||||
const Webhook = require('./Webhook');
|
||||
const { OverwriteTypes, PartialTypes } = require('../util/Constants');
|
||||
const { OverwriteTypes, PartialTypes, AutoModerationRuleTriggerTypes } = require('../util/Constants');
|
||||
const SnowflakeUtil = require('../util/SnowflakeUtil');
|
||||
const Util = require('../util/Util');
|
||||
|
||||
@@ -26,6 +28,8 @@ const Util = require('../util/Util');
|
||||
* * STICKER
|
||||
* * THREAD
|
||||
* * GUILD_SCHEDULED_EVENT
|
||||
* * APPLICATION_COMMAND
|
||||
* * AUTO_MODERATION
|
||||
* @typedef {string} AuditLogTargetType
|
||||
*/
|
||||
|
||||
@@ -49,6 +53,8 @@ const Targets = {
|
||||
STAGE_INSTANCE: 'STAGE_INSTANCE',
|
||||
STICKER: 'STICKER',
|
||||
THREAD: 'THREAD',
|
||||
APPLICATION_COMMAND: 'APPLICATION_COMMAND',
|
||||
AUTO_MODERATION: 'AUTO_MODERATION',
|
||||
UNKNOWN: 'UNKNOWN',
|
||||
};
|
||||
|
||||
@@ -102,6 +108,13 @@ const Targets = {
|
||||
* * THREAD_CREATE: 110
|
||||
* * THREAD_UPDATE: 111
|
||||
* * THREAD_DELETE: 112
|
||||
* * APPLICATION_COMMAND_PERMISSION_UPDATE: 121
|
||||
* * AUTO_MODERATION_RULE_CREATE: 140
|
||||
* * AUTO_MODERATION_RULE_UPDATE: 141
|
||||
* * AUTO_MODERATION_RULE_DELETE: 142
|
||||
* * AUTO_MODERATION_BLOCK_MESSAGE: 143
|
||||
* * AUTO_MODERATION_FLAG_TO_CHANNEL: 144
|
||||
* * AUTO_MODERATION_USER_COMMUNICATION_DISABLED: 145
|
||||
* @typedef {?(number|string)} AuditLogAction
|
||||
* @see {@link https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object-audit-log-events}
|
||||
*/
|
||||
@@ -160,6 +173,13 @@ const Actions = {
|
||||
THREAD_CREATE: 110,
|
||||
THREAD_UPDATE: 111,
|
||||
THREAD_DELETE: 112,
|
||||
APPLICATION_COMMAND_PERMISSION_UPDATE: 121,
|
||||
AUTO_MODERATION_RULE_CREATE: 140,
|
||||
AUTO_MODERATION_RULE_UPDATE: 141,
|
||||
AUTO_MODERATION_RULE_DELETE: 142,
|
||||
AUTO_MODERATION_BLOCK_MESSAGE: 143,
|
||||
AUTO_MODERATION_FLAG_TO_CHANNEL: 144,
|
||||
AUTO_MODERATION_USER_COMMUNICATION_DISABLED: 145,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -193,13 +213,35 @@ class GuildAuditLogs {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cached application commands, includes application commands from other applications
|
||||
* @type {Collection<Snowflake, ApplicationCommand>}
|
||||
* @private
|
||||
*/
|
||||
this.applicationCommands = new Collection();
|
||||
if (data.application_commands) {
|
||||
for (const command of data.application_commands) {
|
||||
this.applicationCommands.set(command.id, new ApplicationCommand(guild.client, command, guild));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Cached auto moderation rules.
|
||||
* @type {Collection<Snowflake, AutoModerationRule>}
|
||||
* @private
|
||||
*/
|
||||
this.autoModerationRules = data.auto_moderation_rules.reduce(
|
||||
(autoModerationRules, autoModerationRule) =>
|
||||
autoModerationRules.set(autoModerationRule.id, guild.autoModerationRules._add(autoModerationRule)),
|
||||
new Collection(),
|
||||
);
|
||||
|
||||
/**
|
||||
* The entries for this guild's audit logs
|
||||
* @type {Collection<Snowflake, GuildAuditLogsEntry>}
|
||||
*/
|
||||
this.entries = new Collection();
|
||||
for (const item of data.audit_log_entries) {
|
||||
const entry = new GuildAuditLogsEntry(this, guild, item);
|
||||
const entry = new GuildAuditLogsEntry(guild, item, this);
|
||||
this.entries.set(entry.id, entry);
|
||||
}
|
||||
}
|
||||
@@ -229,10 +271,12 @@ class GuildAuditLogs {
|
||||
* * A sticker
|
||||
* * A guild scheduled event
|
||||
* * A thread
|
||||
* * An application command
|
||||
* * An auto moderation rule
|
||||
* * An object with an id key if target was deleted
|
||||
* * An object where the keys represent either the new value or the old value
|
||||
* @typedef {?(Object|Guild|Channel|User|Role|Invite|Webhook|GuildEmoji|Message|Integration|StageInstance|Sticker|
|
||||
* GuildScheduledEvent)} AuditLogEntryTarget
|
||||
* GuildScheduledEvent|ApplicationCommand|AutoModerationRule)} AuditLogEntryTarget
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -254,6 +298,8 @@ class GuildAuditLogs {
|
||||
if (target < 100) return Targets.STICKER;
|
||||
if (target < 110) return Targets.GUILD_SCHEDULED_EVENT;
|
||||
if (target < 120) return Targets.THREAD;
|
||||
if (target < 130) return Targets.APPLICATION_COMMAND;
|
||||
if (target >= 140 && target < 150) return Targets.AUTO_MODERATION;
|
||||
return Targets.UNKNOWN;
|
||||
}
|
||||
|
||||
@@ -288,6 +334,8 @@ class GuildAuditLogs {
|
||||
Actions.STICKER_CREATE,
|
||||
Actions.GUILD_SCHEDULED_EVENT_CREATE,
|
||||
Actions.THREAD_CREATE,
|
||||
Actions.AUTO_MODERATION_RULE_CREATE,
|
||||
Actions.AUTO_MODERATION_BLOCK_MESSAGE,
|
||||
].includes(action)
|
||||
) {
|
||||
return 'CREATE';
|
||||
@@ -313,6 +361,7 @@ class GuildAuditLogs {
|
||||
Actions.STICKER_DELETE,
|
||||
Actions.GUILD_SCHEDULED_EVENT_DELETE,
|
||||
Actions.THREAD_DELETE,
|
||||
Actions.AUTO_MODERATION_RULE_DELETE,
|
||||
].includes(action)
|
||||
) {
|
||||
return 'DELETE';
|
||||
@@ -335,6 +384,8 @@ class GuildAuditLogs {
|
||||
Actions.STICKER_UPDATE,
|
||||
Actions.GUILD_SCHEDULED_EVENT_UPDATE,
|
||||
Actions.THREAD_UPDATE,
|
||||
Actions.APPLICATION_COMMAND_PERMISSION_UPDATE,
|
||||
Actions.AUTO_MODERATION_RULE_UPDATE,
|
||||
].includes(action)
|
||||
) {
|
||||
return 'UPDATE';
|
||||
@@ -352,7 +403,7 @@ class GuildAuditLogs {
|
||||
* Audit logs entry.
|
||||
*/
|
||||
class GuildAuditLogsEntry {
|
||||
constructor(logs, guild, data) {
|
||||
constructor(guild, data, logs) {
|
||||
const targetType = GuildAuditLogs.targetType(data.action_type);
|
||||
/**
|
||||
* The target type of this entry
|
||||
@@ -378,6 +429,12 @@ class GuildAuditLogsEntry {
|
||||
*/
|
||||
this.reason = data.reason ?? null;
|
||||
|
||||
/**
|
||||
* The id of the user that executed this entry
|
||||
* @type {?Snowflake}
|
||||
*/
|
||||
this.executorId = data.user_id;
|
||||
|
||||
/**
|
||||
* The user that executed this entry
|
||||
* @type {?User}
|
||||
@@ -385,7 +442,7 @@ class GuildAuditLogsEntry {
|
||||
this.executor = data.user_id
|
||||
? guild.client.options.partials.includes(PartialTypes.USER)
|
||||
? guild.client.users._add({ id: data.user_id })
|
||||
: guild.client.users.cache.get(data.user_id)
|
||||
: guild.client.users.cache.get(data.user_id) ?? null
|
||||
: null;
|
||||
|
||||
/**
|
||||
@@ -398,9 +455,9 @@ class GuildAuditLogsEntry {
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -429,7 +486,6 @@ class GuildAuditLogsEntry {
|
||||
count: Number(data.options.count),
|
||||
};
|
||||
break;
|
||||
|
||||
case Actions.MESSAGE_PIN:
|
||||
case Actions.MESSAGE_UNPIN:
|
||||
this.extra = {
|
||||
@@ -475,11 +531,29 @@ class GuildAuditLogsEntry {
|
||||
channel: guild.client.channels.cache.get(data.options?.channel_id) ?? { id: data.options?.channel_id },
|
||||
};
|
||||
break;
|
||||
|
||||
case Actions.APPLICATION_COMMAND_PERMISSION_UPDATE:
|
||||
this.extra = {
|
||||
applicationId: data.options.application_id,
|
||||
};
|
||||
break;
|
||||
case Actions.AUTO_MODERATION_BLOCK_MESSAGE:
|
||||
case Actions.AUTO_MODERATION_FLAG_TO_CHANNEL:
|
||||
case Actions.AUTO_MODERATION_USER_COMMUNICATION_DISABLED:
|
||||
this.extra = {
|
||||
autoModerationRuleName: data.options.auto_moderation_rule_name,
|
||||
autoModerationRuleTriggerType: AutoModerationRuleTriggerTypes[data.options.auto_moderation_rule_trigger_type],
|
||||
};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* The id of the target of this entry
|
||||
* @type {?Snowflake}
|
||||
*/
|
||||
this.targetId = data.target_id;
|
||||
|
||||
/**
|
||||
* The target of this entry
|
||||
* @type {?AuditLogEntryTarget}
|
||||
@@ -495,12 +569,12 @@ class GuildAuditLogsEntry {
|
||||
} else if (targetType === Targets.USER && data.target_id) {
|
||||
this.target = guild.client.options.partials.includes(PartialTypes.USER)
|
||||
? guild.client.users._add({ id: data.target_id })
|
||||
: guild.client.users.cache.get(data.target_id);
|
||||
: guild.client.users.cache.get(data.target_id) ?? null;
|
||||
} else if (targetType === Targets.GUILD) {
|
||||
this.target = guild.client.guilds.cache.get(data.target_id);
|
||||
} else if (targetType === Targets.WEBHOOK) {
|
||||
this.target =
|
||||
logs.webhooks.get(data.target_id) ??
|
||||
logs?.webhooks.get(data.target_id) ??
|
||||
new Webhook(
|
||||
guild.client,
|
||||
this.changes.reduce(
|
||||
@@ -535,10 +609,10 @@ class GuildAuditLogsEntry {
|
||||
this.target =
|
||||
data.action_type === Actions.MESSAGE_BULK_DELETE
|
||||
? guild.channels.cache.get(data.target_id) ?? { id: data.target_id }
|
||||
: guild.client.users.cache.get(data.target_id);
|
||||
: guild.client.users.cache.get(data.target_id) ?? null;
|
||||
} else if (targetType === Targets.INTEGRATION) {
|
||||
this.target =
|
||||
logs.integrations.get(data.target_id) ??
|
||||
logs?.integrations.get(data.target_id) ??
|
||||
new Integration(
|
||||
guild.client,
|
||||
this.changes.reduce(
|
||||
@@ -603,6 +677,22 @@ class GuildAuditLogsEntry {
|
||||
{ id: data.target_id, guild_id: guild.id },
|
||||
),
|
||||
);
|
||||
} else if (targetType === Targets.APPLICATION_COMMAND) {
|
||||
this.target = logs?.applicationCommands.get(data.target_id) ?? { id: data.target_id };
|
||||
} else if (targetType === Targets.AUTO_MODERATION) {
|
||||
this.target =
|
||||
guild.autoModerationRules.cache.get(data.target_id) ??
|
||||
new AutoModerationRule(
|
||||
guild.client,
|
||||
this.changes.reduce(
|
||||
(o, c) => {
|
||||
o[c.key] = c.new ?? c.old;
|
||||
return o;
|
||||
},
|
||||
{ id: data.target_id, guild_id: guild.id },
|
||||
),
|
||||
guild,
|
||||
);
|
||||
} else if (data.target_id) {
|
||||
this.target = guild[`${targetType.toLowerCase()}s`]?.cache.get(data.target_id) ?? { id: data.target_id };
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
const { Channel } = require('./Channel');
|
||||
const PermissionOverwrites = require('./PermissionOverwrites');
|
||||
const { Error } = require('../errors');
|
||||
const PermissionOverwriteManager = require('../managers/PermissionOverwriteManager');
|
||||
const { ChannelTypes, VoiceBasedChannelTypes } = require('../util/Constants');
|
||||
const { VoiceBasedChannelTypes } = require('../util/Constants');
|
||||
const Permissions = require('../util/Permissions');
|
||||
const Util = require('../util/Util');
|
||||
|
||||
/**
|
||||
* Represents a guild channel from any of the following:
|
||||
@@ -16,6 +14,7 @@ const Util = require('../util/Util');
|
||||
* - {@link NewsChannel}
|
||||
* - {@link StoreChannel}
|
||||
* - {@link StageChannel}
|
||||
* - {@link ForumChannel}
|
||||
* @extends {Channel}
|
||||
* @abstract
|
||||
*/
|
||||
@@ -262,27 +261,6 @@ class GuildChannel extends Channel {
|
||||
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.
|
||||
* @param {ChannelData} data The new data for the channel
|
||||
@@ -294,64 +272,8 @@ class GuildChannel extends Channel {
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async edit(data, reason) {
|
||||
data.parent &&= this.client.channels.resolveId(data.parent);
|
||||
|
||||
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;
|
||||
edit(data, reason) {
|
||||
return this.guild.channels.edit(this, data, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -415,30 +337,10 @@ class GuildChannel extends Channel {
|
||||
* .then(newChannel => console.log(`Channel's new position is ${newChannel.position}`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async setPosition(position, { relative, reason } = {}) {
|
||||
const updatedChannels = await Util.setPosition(
|
||||
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;
|
||||
setPosition(position, options = {}) {
|
||||
return this.guild.channels.setPosition(this, position, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @typedef {GuildChannelCreateOptions} GuildChannelCloneOptions
|
||||
@@ -513,7 +415,7 @@ class GuildChannel extends Channel {
|
||||
|
||||
// This flag allows managing even if timed out
|
||||
if (permissions.has(Permissions.FLAGS.ADMINISTRATOR, false)) return true;
|
||||
if (this.guild.me.communicationDisabledUntilTimestamp > Date.now()) return false;
|
||||
if (this.guild.members.me.communicationDisabledUntilTimestamp > Date.now()) return false;
|
||||
|
||||
const bitfield = VoiceBasedChannelTypes.includes(this.type)
|
||||
? Permissions.FLAGS.MANAGE_CHANNELS | Permissions.FLAGS.CONNECT
|
||||
@@ -544,7 +446,7 @@ class GuildChannel extends Channel {
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async delete(reason) {
|
||||
await this.client.api.channels(this.id).delete({ reason });
|
||||
await this.guild.channels.delete(this.id, reason);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,8 +55,8 @@ class GuildEmoji extends BaseGuildEmoji {
|
||||
* @readonly
|
||||
*/
|
||||
get deletable() {
|
||||
if (!this.guild.me) throw new Error('GUILD_UNCACHED_ME');
|
||||
return !this.managed && this.guild.me.permissions.has(Permissions.FLAGS.MANAGE_EMOJIS_AND_STICKERS);
|
||||
if (!this.guild.members.me) throw new Error('GUILD_UNCACHED_ME');
|
||||
return !this.managed && this.guild.members.me.permissions.has(Permissions.FLAGS.MANAGE_EMOJIS_AND_STICKERS);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,18 +72,8 @@ class GuildEmoji extends BaseGuildEmoji {
|
||||
* Fetches the author for this emoji
|
||||
* @returns {Promise<User>}
|
||||
*/
|
||||
async fetchAuthor() {
|
||||
if (this.managed) {
|
||||
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;
|
||||
fetchAuthor() {
|
||||
return this.guild.emojis.fetchAuthor(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,7 +127,7 @@ class GuildEmoji extends BaseGuildEmoji {
|
||||
* @returns {Promise<GuildEmoji>}
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ const VoiceState = require('./VoiceState');
|
||||
const TextBasedChannel = require('./interfaces/TextBasedChannel');
|
||||
const { Error } = require('../errors');
|
||||
const GuildMemberRoleManager = require('../managers/GuildMemberRoleManager');
|
||||
const GuildMemberFlags = require('../util/GuildMemberFlags');
|
||||
const Permissions = require('../util/Permissions');
|
||||
|
||||
/**
|
||||
@@ -95,6 +96,15 @@ class GuildMember extends Base {
|
||||
this.communicationDisabledUntilTimestamp =
|
||||
data.communication_disabled_until && Date.parse(data.communication_disabled_until);
|
||||
}
|
||||
if ('flags' in data) {
|
||||
/**
|
||||
* The flags of this member
|
||||
* @type {Readonly<GuildMemberFlags>}
|
||||
*/
|
||||
this.flags = new GuildMemberFlags(data.flags).freeze();
|
||||
} else {
|
||||
this.flags ??= new GuildMemberFlags().freeze();
|
||||
}
|
||||
}
|
||||
|
||||
_clone() {
|
||||
@@ -272,8 +282,8 @@ class GuildMember extends Base {
|
||||
if (this.user.id === this.guild.ownerId) return false;
|
||||
if (this.user.id === this.client.user.id) return false;
|
||||
if (this.client.user.id === this.guild.ownerId) return true;
|
||||
if (!this.guild.me) throw new Error('GUILD_UNCACHED_ME');
|
||||
return this.guild.me.roles.highest.comparePositionTo(this.roles.highest) > 0;
|
||||
if (!this.guild.members.me) throw new Error('GUILD_UNCACHED_ME');
|
||||
return this.guild.members.me.roles.highest.comparePositionTo(this.roles.highest) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -282,7 +292,7 @@ class GuildMember extends Base {
|
||||
* @readonly
|
||||
*/
|
||||
get kickable() {
|
||||
return this.manageable && this.guild.me.permissions.has(Permissions.FLAGS.KICK_MEMBERS);
|
||||
return this.manageable && this.guild.members.me.permissions.has(Permissions.FLAGS.KICK_MEMBERS);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -291,7 +301,7 @@ class GuildMember extends Base {
|
||||
* @readonly
|
||||
*/
|
||||
get bannable() {
|
||||
return this.manageable && this.guild.me.permissions.has(Permissions.FLAGS.BAN_MEMBERS);
|
||||
return this.manageable && this.guild.members.me.permissions.has(Permissions.FLAGS.BAN_MEMBERS);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -300,7 +310,11 @@ class GuildMember extends Base {
|
||||
* @readonly
|
||||
*/
|
||||
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.members.me?.permissions.has(Permissions.FLAGS.MODERATE_MEMBERS) ?? false)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -343,6 +357,16 @@ class GuildMember extends Base {
|
||||
return this.edit({ nick }, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flags for this member.
|
||||
* @param {GuildMemberFlagsResolvable} flags The flags to set
|
||||
* @param {string} [reason] Reason for setting the flags
|
||||
* @returns {Promise<GuildMember>}
|
||||
*/
|
||||
setFlags(flags, reason) {
|
||||
return this.edit({ flags, reason });
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DM channel between the client and this member.
|
||||
* @param {boolean} [force=false] Whether to skip the cache check and request the API
|
||||
@@ -374,8 +398,8 @@ class GuildMember extends Base {
|
||||
* @param {BanOptions} [options] Options for the ban
|
||||
* @returns {Promise<GuildMember>}
|
||||
* @example
|
||||
* // ban a guild member
|
||||
* guildMember.ban({ days: 7, reason: 'They deserved it' })
|
||||
* // Ban a guild member, deleting a week's worth of messages
|
||||
* guildMember.ban({ deleteMessageSeconds: 60 * 60 * 24 * 7, reason: 'They deserved it' })
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
@@ -442,6 +466,7 @@ class GuildMember extends Base {
|
||||
this.avatar === member.avatar &&
|
||||
this.pending === member.pending &&
|
||||
this.communicationDisabledUntilTimestamp === member.communicationDisabledUntilTimestamp &&
|
||||
this.flags.equals(member.flags) &&
|
||||
(this._roles === member._roles ||
|
||||
(this._roles.length === member._roles.length && this._roles.every((role, i) => role === member._roles[i])))
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const Base = require('./Base');
|
||||
const GuildPreviewEmoji = require('./GuildPreviewEmoji');
|
||||
const { Sticker } = require('./Sticker');
|
||||
const SnowflakeUtil = require('../util/SnowflakeUtil');
|
||||
|
||||
/**
|
||||
@@ -103,6 +104,15 @@ class GuildPreview extends Base {
|
||||
for (const emoji of data.emojis) {
|
||||
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
|
||||
|
||||
@@ -156,6 +156,25 @@ class GuildScheduledEvent extends Base {
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,11 +15,13 @@ const IntegrationApplication = require('./IntegrationApplication');
|
||||
* * `twitch`
|
||||
* * `youtube`
|
||||
* * `discord`
|
||||
* * `guild_subscription`
|
||||
* @typedef {string} IntegrationType
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a guild integration.
|
||||
* Represents a guild integration.
|
||||
* @extends {Base}
|
||||
*/
|
||||
class Integration extends Base {
|
||||
constructor(client, data, guild) {
|
||||
|
||||
@@ -54,6 +54,7 @@ class IntegrationApplication extends Application {
|
||||
/**
|
||||
* The application's summary
|
||||
* @type {?string}
|
||||
* @deprecated This property is no longer being sent by the API.
|
||||
*/
|
||||
this.summary = data.summary;
|
||||
} else {
|
||||
|
||||
@@ -69,11 +69,65 @@ class Interaction extends Base {
|
||||
*/
|
||||
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
|
||||
* @type {?Readonly<Permissions>}
|
||||
*/
|
||||
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';
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}
|
||||
* @returns {boolean}
|
||||
@@ -213,6 +275,16 @@ class Interaction extends Base {
|
||||
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;
|
||||
|
||||
@@ -7,9 +7,9 @@ const { InteractionTypes, MessageComponentTypes } = require('../util/Constants')
|
||||
|
||||
/**
|
||||
* @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 {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 {number} [max] The maximum total amount of interactions to collect
|
||||
* @property {number} [maxComponents] The maximum number of components to collect
|
||||
|
||||
@@ -197,8 +197,11 @@ class Invite extends Base {
|
||||
this.createdTimestamp ??= null;
|
||||
}
|
||||
|
||||
if ('expires_at' in data) this._expiresTimestamp = new Date(data.expires_at).getTime();
|
||||
else this._expiresTimestamp ??= null;
|
||||
if ('expires_at' in data) {
|
||||
this._expiresTimestamp = data.expires_at && Date.parse(data.expires_at);
|
||||
} else {
|
||||
this._expiresTimestamp ??= null;
|
||||
}
|
||||
|
||||
if ('stage_instance' in data) {
|
||||
/**
|
||||
@@ -238,10 +241,10 @@ class Invite extends Base {
|
||||
get deletable() {
|
||||
const guild = this.guild;
|
||||
if (!guild || !this.client.guilds.cache.has(guild.id)) return false;
|
||||
if (!guild.me) throw new Error('GUILD_UNCACHED_ME');
|
||||
if (!guild.members.me) throw new Error('GUILD_UNCACHED_ME');
|
||||
return (
|
||||
this.channel.permissionsFor(this.client.user).has(Permissions.FLAGS.MANAGE_CHANNELS, false) ||
|
||||
guild.me.permissions.has(Permissions.FLAGS.MANAGE_GUILD)
|
||||
guild.members.me.permissions.has(Permissions.FLAGS.MANAGE_GUILD)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ const ReactionCollector = require('./ReactionCollector');
|
||||
const { Sticker } = require('./Sticker');
|
||||
const { Error } = require('../errors');
|
||||
const ReactionManager = require('../managers/ReactionManager');
|
||||
const { InteractionTypes, MessageTypes, SystemMessageTypes } = require('../util/Constants');
|
||||
const { InteractionTypes, MessageTypes, SystemMessageTypes, MaxBulkDeletableMessageAge } = require('../util/Constants');
|
||||
const MessageFlags = require('../util/MessageFlags');
|
||||
const Permissions = require('../util/Permissions');
|
||||
const SnowflakeUtil = require('../util/SnowflakeUtil');
|
||||
@@ -58,6 +58,17 @@ class Message extends Base {
|
||||
*/
|
||||
this.id = data.id;
|
||||
|
||||
if ('position' in data) {
|
||||
/**
|
||||
* A generally increasing integer (there may be gaps or duplicates) that represents
|
||||
* the approximate position of the message in a thread.
|
||||
* @type {?number}
|
||||
*/
|
||||
this.position = data.position;
|
||||
} else {
|
||||
this.position ??= null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The timestamp the message was sent at
|
||||
* @type {number}
|
||||
@@ -331,7 +342,8 @@ class Message extends Base {
|
||||
* @typedef {Object} MessageInteraction
|
||||
* @property {Snowflake} id The interaction's id
|
||||
* @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
|
||||
*/
|
||||
|
||||
@@ -383,7 +395,7 @@ class Message extends Base {
|
||||
|
||||
/**
|
||||
* The channel that the message was sent in
|
||||
* @type {TextChannel|DMChannel|NewsChannel|ThreadChannel}
|
||||
* @type {TextBasedChannels}
|
||||
* @readonly
|
||||
*/
|
||||
get channel() {
|
||||
@@ -620,7 +632,26 @@ class Message extends Base {
|
||||
return Boolean(
|
||||
this.author.id === this.client.user.id ||
|
||||
(permissions.has(Permissions.FLAGS.MANAGE_MESSAGES, false) &&
|
||||
this.guild.me.communicationDisabledUntilTimestamp < Date.now()),
|
||||
this.guild.members.me.communicationDisabledUntilTimestamp < Date.now()),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the message is bulk deletable by the client user
|
||||
* @type {boolean}
|
||||
* @readonly
|
||||
* @example
|
||||
* // Filter for bulk deletable messages
|
||||
* channel.bulkDelete(messages.filter(message => message.bulkDeletable));
|
||||
*/
|
||||
get bulkDeletable() {
|
||||
const permissions = this.channel?.permissionsFor(this.client.user);
|
||||
return (
|
||||
(this.inGuild() &&
|
||||
Date.now() - this.createdTimestamp < MaxBulkDeletableMessageAge &&
|
||||
this.deletable &&
|
||||
permissions?.has(Permissions.FLAGS.MANAGE_MESSAGES, false)) ??
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
@@ -720,6 +751,7 @@ class Message extends Base {
|
||||
|
||||
/**
|
||||
* Pins this message to the channel's pinned messages.
|
||||
* @param {string} [reason] Reason for pinning
|
||||
* @returns {Promise<Message>}
|
||||
* @example
|
||||
* // Pin a message
|
||||
@@ -727,14 +759,15 @@ class Message extends Base {
|
||||
* .then(console.log)
|
||||
* .catch(console.error)
|
||||
*/
|
||||
async pin() {
|
||||
async pin(reason) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpins this message from the channel's pinned messages.
|
||||
* @param {string} [reason] Reason for unpinning
|
||||
* @returns {Promise<Message>}
|
||||
* @example
|
||||
* // Unpin a message
|
||||
@@ -742,9 +775,9 @@ class Message extends Base {
|
||||
* .then(console.log)
|
||||
* .catch(console.error)
|
||||
*/
|
||||
async unpin() {
|
||||
async unpin(reason) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -833,9 +866,10 @@ class Message extends Base {
|
||||
* archived. This can be:
|
||||
* * `60` (1 hour)
|
||||
* * `1440` (1 day)
|
||||
* * `4320` (3 days) <warn>This is only available when the guild has the `THREE_DAY_THREAD_ARCHIVE` feature.</warn>
|
||||
* * `10080` (7 days) <warn>This is only available when the guild has the `SEVEN_DAY_THREAD_ARCHIVE` feature.</warn>
|
||||
* * `'MAX'` Based on the guild's features
|
||||
* * `4320` (3 days)
|
||||
* * `10080` (7 days)
|
||||
* * `'MAX'` (7 days)
|
||||
* <warn>This option is deprecated and will be removed in the next major version.</warn>
|
||||
* @typedef {number|string} ThreadAutoArchiveDuration
|
||||
*/
|
||||
|
||||
@@ -851,7 +885,7 @@ class Message extends Base {
|
||||
|
||||
/**
|
||||
* Create a new public thread from this message
|
||||
* @see ThreadManager#create
|
||||
* @see GuildTextThreadManager#create
|
||||
* @param {StartThreadOptions} [options] Options for starting a thread on this message
|
||||
* @returns {Promise<ThreadChannel>}
|
||||
*/
|
||||
|
||||
@@ -12,14 +12,16 @@ class MessageActionRow extends BaseMessageComponent {
|
||||
* Components that can be placed in an action row
|
||||
* * MessageButton
|
||||
* * MessageSelectMenu
|
||||
* @typedef {MessageButton|MessageSelectMenu} MessageActionRowComponent
|
||||
* * TextInputComponent
|
||||
* @typedef {MessageButton|MessageSelectMenu|TextInputComponent} MessageActionRowComponent
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options for components that can be placed in an action row
|
||||
* * MessageButtonOptions
|
||||
* * MessageSelectMenuOptions
|
||||
* @typedef {MessageButtonOptions|MessageSelectMenuOptions} MessageActionRowComponentOptions
|
||||
* * TextInputComponentOptions
|
||||
* @typedef {MessageButtonOptions|MessageSelectMenuOptions|TextInputComponentOptions} MessageActionRowComponentOptions
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -124,7 +124,7 @@ class MessageAttachment {
|
||||
|
||||
if ('content_type' in data) {
|
||||
/**
|
||||
* This media type of this attachment
|
||||
* The media type of this attachment
|
||||
* @type {?string}
|
||||
*/
|
||||
this.contentType = data.content_type;
|
||||
|
||||
@@ -101,6 +101,8 @@ class MessageComponentInteraction extends Interaction {
|
||||
followUp() {}
|
||||
deferUpdate() {}
|
||||
update() {}
|
||||
showModal() {}
|
||||
awaitModalSubmit() {}
|
||||
}
|
||||
|
||||
InteractionResponses.applyToClass(MessageComponentInteraction);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user