Discord.js v13.7
This commit is contained in:
parent
fc7f02e85b
commit
c201e7da69
@ -14,6 +14,8 @@
|
||||
|
||||
## About
|
||||
|
||||
<strong>Welcome to `discord.js-selfbot-v13@v2`, based on `discord.js@13.7.0`</strong>
|
||||
|
||||
- discord.js-selfbot-v13 is a [Node.js](https://nodejs.org) module that allows user accounts to interact with the Discord API v9.
|
||||
|
||||
|
||||
@ -28,6 +30,7 @@
|
||||
### <strong>I don't take any responsibility for blocked Discord accounts that used this module.</strong>
|
||||
### <strong>Using this on a user account is prohibited by the [Discord TOS](https://discord.com/terms) and can lead to the account block.</strong>
|
||||
|
||||
|
||||
### <strong>[Document Website (recommend)](https://www.discordjs-self-v13.cf)</strong>
|
||||
But if you want to see some specific notes (with pictures) you can go to [here](https://github.com/aiko-chan-ai/discord.js-selfbot-v13/blob/main/Document/DOCUMENT.md) or go to [wiki](https://github.com/aiko-chan-ai/discord.js-selfbot-v13/wiki)
|
||||
### <strong>[Risky actions](https://github.com/Merubokkusu/Discord-S.C.U.M/issues/66)</strong>
|
||||
@ -39,7 +42,7 @@ But if you want to see some specific notes (with pictures) you can go to [here](
|
||||
- [X] Profile Editing (Name, Status, Avatar, Bio, Rich-Presence, etc.)
|
||||
- [X] Interactions (slash commands, buttons, etc.)
|
||||
- [X] Voice Channel (Join, Leave, Speak, etc.)
|
||||
- [ ] Improve documentation (maybe)
|
||||
- [X] Documentation
|
||||
- [ ] Add more guild http api wraps
|
||||
- [ ] Audio / Video call
|
||||
- [ ] Everything
|
||||
@ -55,7 +58,7 @@ npm install discord.js-selfbot-v13@latest
|
||||
|
||||
```js
|
||||
const { Client } = require('discord.js-selfbot-v13');
|
||||
const client = new Client(); // Intents and Partials are already set so you don't have to define them
|
||||
const client = new Client(); // All partials are loaded automatically
|
||||
|
||||
client.on('ready', async () => {
|
||||
console.log(`${client.user.username} is ready!`);
|
||||
|
File diff suppressed because one or more lines are too long
202
package-lock.json
generated
202
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "discord.js-selfbot-v13",
|
||||
"version": "1.4.31",
|
||||
"version": "2.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "discord.js-selfbot-v13",
|
||||
"version": "1.4.31",
|
||||
"version": "2.0.0",
|
||||
"license": "GNU General Public License v3.0",
|
||||
"dependencies": {
|
||||
"@discordjs/builders": "^0.13.0",
|
||||
@ -21,21 +21,21 @@
|
||||
"bufferutil": "^4.0.6",
|
||||
"chalk": "^4.1.2",
|
||||
"discord-api-types": "^0.32.0",
|
||||
"discord-bettermarkdown": "^1.1.0",
|
||||
"discord-bettermarkdown": "^1.2.0",
|
||||
"discord-rpc-contructor": "^1.1.5",
|
||||
"discord.js": "^13.6.0",
|
||||
"discord.js": "^13.7.0",
|
||||
"form-data": "^4.0.0",
|
||||
"i": "^0.3.7",
|
||||
"json-bigint": "^1.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash.snakecase": "^4.1.1",
|
||||
"node-fetch": "^2.6.1",
|
||||
"npm": "^8.8.0",
|
||||
"npm": "^8.10.0",
|
||||
"qrcode-terminal": "^0.12.0",
|
||||
"safe-base64": "^2.0.1-0",
|
||||
"string_decoder": "^1.3.0",
|
||||
"string-similarity": "^4.0.4",
|
||||
"undici": "^5.1.1",
|
||||
"undici": "^5.2.0",
|
||||
"utf-8-validate": "^5.0.9",
|
||||
"ws": "^8.5.0"
|
||||
},
|
||||
@ -47,13 +47,13 @@
|
||||
"@types/node": "^16.11.12",
|
||||
"conventional-changelog-cli": "^2.2.2",
|
||||
"dtslint": "^4.2.1",
|
||||
"eslint": "^8.5.0",
|
||||
"eslint": "^8.15.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-import": "^2.25.3",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"husky": "^7.0.4",
|
||||
"is-ci": "^3.0.1",
|
||||
"jest": "^28.0.1",
|
||||
"jest": "^28.1.0",
|
||||
"lint-staged": "^12.1.4",
|
||||
"prettier": "^2.5.1",
|
||||
"tsd": "^0.20.0",
|
||||
@ -4436,57 +4436,29 @@
|
||||
}
|
||||
},
|
||||
"node_modules/discord.js": {
|
||||
"version": "13.6.0",
|
||||
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.6.0.tgz",
|
||||
"integrity": "sha512-tXNR8zgsEPxPBvGk3AQjJ9ljIIC6/LOPjzKwpwz8Y1Q2X66Vi3ZqFgRHYwnHKC0jC0F+l4LzxlhmOJsBZDNg9g==",
|
||||
"version": "13.7.0",
|
||||
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.7.0.tgz",
|
||||
"integrity": "sha512-iV/An3FEB/CiBGdjWHRtgskM4UuWPq5vjhjKsrQhdVU16dbKrBxA+eIV2HWA07B3tXUGM6eco1wkr42gxxV1BA==",
|
||||
"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.13.0",
|
||||
"@discordjs/collection": "^0.6.0",
|
||||
"@sapphire/async-queue": "^1.3.1",
|
||||
"@types/node-fetch": "^2.6.1",
|
||||
"@types/ws": "^8.5.3",
|
||||
"discord-api-types": "^0.30.0",
|
||||
"form-data": "^4.0.0",
|
||||
"node-fetch": "^2.6.1",
|
||||
"ws": "^8.4.0"
|
||||
"ws": "^8.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.6.0",
|
||||
"npm": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/discord.js/node_modules/@discordjs/builders": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.11.0.tgz",
|
||||
"integrity": "sha512-ZTB8yJdJKrKlq44dpWkNUrAtEJEq0gqpb7ASdv4vmq6/mZal5kOv312hQ56I/vxwMre+VIkoHquNUAfnTbiYtg==",
|
||||
"dependencies": {
|
||||
"@sindresorhus/is": "^4.2.0",
|
||||
"discord-api-types": "^0.26.0",
|
||||
"ts-mixer": "^6.0.0",
|
||||
"tslib": "^2.3.1",
|
||||
"zod": "^3.11.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0",
|
||||
"npm": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/discord.js/node_modules/@discordjs/collection": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.4.0.tgz",
|
||||
"integrity": "sha512-zmjq+l/rV35kE6zRrwe8BHqV78JvIh2ybJeZavBi5NySjWXqN3hmmAKg7kYMMXSeiWtSsMoZ/+MQi0DiQWy2lw==",
|
||||
"engines": {
|
||||
"node": ">=16.0.0",
|
||||
"npm": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/discord.js/node_modules/discord-api-types": {
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.26.1.tgz",
|
||||
"integrity": "sha512-T5PdMQ+Y1MEECYMV5wmyi9VEYPagEDEi4S0amgsszpWY0VB9JJ/hEvM6BgLhbdnKky4gfmZEXtEEtojN8ZKJQQ==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
"version": "0.30.0",
|
||||
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.30.0.tgz",
|
||||
"integrity": "sha512-wYst0jrT8EJs2tVlwUTQ2xT0oWMjUrRMpFTkNY3NMleWyQNHgWaKhqFfxdLPdC2im9IuR5EsxcEgjhf/npeftw=="
|
||||
},
|
||||
"node_modules/dmd": {
|
||||
"version": "4.0.6",
|
||||
@ -9317,9 +9289,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/npm": {
|
||||
"version": "8.9.0",
|
||||
"resolved": "https://registry.npmjs.org/npm/-/npm-8.9.0.tgz",
|
||||
"integrity": "sha512-4mhU5nEv7ktvHmJnM2nmWP2Zk4cCsD26imX+dvZ76HOuFUnIpU6+i1MWuoMg8N/xWHQgB0d2/ybWEGgJR9M/pw==",
|
||||
"version": "8.10.0",
|
||||
"resolved": "https://registry.npmjs.org/npm/-/npm-8.10.0.tgz",
|
||||
"integrity": "sha512-6oo65q9Quv9mRPGZJufmSH+C/UFdgelwzRXiglT/2mDB50zdy/lZK5dFY0TJ9fJ/8gHqnxcX1NM206KLjTBMlQ==",
|
||||
"bundleDependencies": [
|
||||
"@isaacs/string-locale-compare",
|
||||
"@npmcli/arborist",
|
||||
@ -9428,7 +9400,7 @@
|
||||
"libnpmsearch": "^5.0.2",
|
||||
"libnpmteam": "^4.0.2",
|
||||
"libnpmversion": "^3.0.1",
|
||||
"make-fetch-happen": "^10.1.2",
|
||||
"make-fetch-happen": "^10.1.3",
|
||||
"minipass": "^3.1.6",
|
||||
"minipass-pipeline": "^1.2.4",
|
||||
"mkdirp": "^1.0.4",
|
||||
@ -9550,7 +9522,7 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/npm/node_modules/@npmcli/arborist": {
|
||||
"version": "5.1.1",
|
||||
"version": "5.2.0",
|
||||
"inBundle": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
@ -9904,7 +9876,7 @@
|
||||
}
|
||||
},
|
||||
"node_modules/npm/node_modules/builtins": {
|
||||
"version": "5.0.0",
|
||||
"version": "5.0.1",
|
||||
"inBundle": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -10293,7 +10265,7 @@
|
||||
}
|
||||
},
|
||||
"node_modules/npm/node_modules/https-proxy-agent": {
|
||||
"version": "5.0.0",
|
||||
"version": "5.0.1",
|
||||
"inBundle": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -10396,7 +10368,7 @@
|
||||
}
|
||||
},
|
||||
"node_modules/npm/node_modules/ip": {
|
||||
"version": "1.1.5",
|
||||
"version": "1.1.8",
|
||||
"inBundle": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@ -10420,7 +10392,7 @@
|
||||
}
|
||||
},
|
||||
"node_modules/npm/node_modules/is-core-module": {
|
||||
"version": "2.8.1",
|
||||
"version": "2.9.0",
|
||||
"inBundle": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -10470,7 +10442,7 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/npm/node_modules/just-diff": {
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2",
|
||||
"inBundle": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@ -10635,7 +10607,7 @@
|
||||
}
|
||||
},
|
||||
"node_modules/npm/node_modules/lru-cache": {
|
||||
"version": "7.8.1",
|
||||
"version": "7.9.0",
|
||||
"inBundle": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
@ -10643,7 +10615,7 @@
|
||||
}
|
||||
},
|
||||
"node_modules/npm/node_modules/make-fetch-happen": {
|
||||
"version": "10.1.2",
|
||||
"version": "10.1.3",
|
||||
"inBundle": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
@ -10952,7 +10924,7 @@
|
||||
}
|
||||
},
|
||||
"node_modules/npm/node_modules/npm-packlist": {
|
||||
"version": "5.0.2",
|
||||
"version": "5.0.3",
|
||||
"inBundle": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
@ -11384,13 +11356,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/npm/node_modules/socks-proxy-agent": {
|
||||
"version": "6.1.1",
|
||||
"version": "6.2.0",
|
||||
"inBundle": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "^6.0.2",
|
||||
"debug": "^4.3.1",
|
||||
"socks": "^2.6.1"
|
||||
"debug": "^4.3.3",
|
||||
"socks": "^2.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
@ -14191,9 +14163,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.1.1.tgz",
|
||||
"integrity": "sha512-CmK9JzLSMGx+2msOao8LhkKn3J7eKo2M50v0KZQ2XbiHcGqLS1HiIj01ceIm3jbUYlspw/FTSb6nMdSNyvVyaQ==",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.2.0.tgz",
|
||||
"integrity": "sha512-XY6+NS3WH9b3TKOHeNz2CjR+qrVz/k4fO9g3etPpLozRvULoQmZ1+dk9JbIz40ehn27xzFk4jYVU2MU3Nle62A==",
|
||||
"engines": {
|
||||
"node": ">=12.18"
|
||||
}
|
||||
@ -14690,14 +14662,6 @@
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.14.2",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.14.2.tgz",
|
||||
"integrity": "sha512-iF+wrtzz7fQfkmn60PG6XFxaWBhYYKzp2i+nv24WbLUWb2JjymdkHlzBwP0erpc78WotwP5g9AAu7Sk8GWVVNw==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
@ -18144,42 +18108,25 @@
|
||||
}
|
||||
},
|
||||
"discord.js": {
|
||||
"version": "13.6.0",
|
||||
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.6.0.tgz",
|
||||
"integrity": "sha512-tXNR8zgsEPxPBvGk3AQjJ9ljIIC6/LOPjzKwpwz8Y1Q2X66Vi3ZqFgRHYwnHKC0jC0F+l4LzxlhmOJsBZDNg9g==",
|
||||
"version": "13.7.0",
|
||||
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.7.0.tgz",
|
||||
"integrity": "sha512-iV/An3FEB/CiBGdjWHRtgskM4UuWPq5vjhjKsrQhdVU16dbKrBxA+eIV2HWA07B3tXUGM6eco1wkr42gxxV1BA==",
|
||||
"requires": {
|
||||
"@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.13.0",
|
||||
"@discordjs/collection": "^0.6.0",
|
||||
"@sapphire/async-queue": "^1.3.1",
|
||||
"@types/node-fetch": "^2.6.1",
|
||||
"@types/ws": "^8.5.3",
|
||||
"discord-api-types": "^0.30.0",
|
||||
"form-data": "^4.0.0",
|
||||
"node-fetch": "^2.6.1",
|
||||
"ws": "^8.4.0"
|
||||
"ws": "^8.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@discordjs/builders": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.11.0.tgz",
|
||||
"integrity": "sha512-ZTB8yJdJKrKlq44dpWkNUrAtEJEq0gqpb7ASdv4vmq6/mZal5kOv312hQ56I/vxwMre+VIkoHquNUAfnTbiYtg==",
|
||||
"requires": {
|
||||
"@sindresorhus/is": "^4.2.0",
|
||||
"discord-api-types": "^0.26.0",
|
||||
"ts-mixer": "^6.0.0",
|
||||
"tslib": "^2.3.1",
|
||||
"zod": "^3.11.6"
|
||||
}
|
||||
},
|
||||
"@discordjs/collection": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.4.0.tgz",
|
||||
"integrity": "sha512-zmjq+l/rV35kE6zRrwe8BHqV78JvIh2ybJeZavBi5NySjWXqN3hmmAKg7kYMMXSeiWtSsMoZ/+MQi0DiQWy2lw=="
|
||||
},
|
||||
"discord-api-types": {
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.26.1.tgz",
|
||||
"integrity": "sha512-T5PdMQ+Y1MEECYMV5wmyi9VEYPagEDEi4S0amgsszpWY0VB9JJ/hEvM6BgLhbdnKky4gfmZEXtEEtojN8ZKJQQ=="
|
||||
"version": "0.30.0",
|
||||
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.30.0.tgz",
|
||||
"integrity": "sha512-wYst0jrT8EJs2tVlwUTQ2xT0oWMjUrRMpFTkNY3NMleWyQNHgWaKhqFfxdLPdC2im9IuR5EsxcEgjhf/npeftw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -21881,9 +21828,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"npm": {
|
||||
"version": "8.9.0",
|
||||
"resolved": "https://registry.npmjs.org/npm/-/npm-8.9.0.tgz",
|
||||
"integrity": "sha512-4mhU5nEv7ktvHmJnM2nmWP2Zk4cCsD26imX+dvZ76HOuFUnIpU6+i1MWuoMg8N/xWHQgB0d2/ybWEGgJR9M/pw==",
|
||||
"version": "8.10.0",
|
||||
"resolved": "https://registry.npmjs.org/npm/-/npm-8.10.0.tgz",
|
||||
"integrity": "sha512-6oo65q9Quv9mRPGZJufmSH+C/UFdgelwzRXiglT/2mDB50zdy/lZK5dFY0TJ9fJ/8gHqnxcX1NM206KLjTBMlQ==",
|
||||
"requires": {
|
||||
"@isaacs/string-locale-compare": "^1.1.0",
|
||||
"@npmcli/arborist": "^5.0.4",
|
||||
@ -21920,7 +21867,7 @@
|
||||
"libnpmsearch": "^5.0.2",
|
||||
"libnpmteam": "^4.0.2",
|
||||
"libnpmversion": "^3.0.1",
|
||||
"make-fetch-happen": "^10.1.2",
|
||||
"make-fetch-happen": "^10.1.3",
|
||||
"minipass": "^3.1.6",
|
||||
"minipass-pipeline": "^1.2.4",
|
||||
"mkdirp": "^1.0.4",
|
||||
@ -21971,7 +21918,7 @@
|
||||
"bundled": true
|
||||
},
|
||||
"@npmcli/arborist": {
|
||||
"version": "5.1.1",
|
||||
"version": "5.2.0",
|
||||
"bundled": true,
|
||||
"requires": {
|
||||
"@isaacs/string-locale-compare": "^1.1.0",
|
||||
@ -22217,7 +22164,7 @@
|
||||
}
|
||||
},
|
||||
"builtins": {
|
||||
"version": "5.0.0",
|
||||
"version": "5.0.1",
|
||||
"bundled": true,
|
||||
"requires": {
|
||||
"semver": "^7.0.0"
|
||||
@ -22481,7 +22428,7 @@
|
||||
}
|
||||
},
|
||||
"https-proxy-agent": {
|
||||
"version": "5.0.0",
|
||||
"version": "5.0.1",
|
||||
"bundled": true,
|
||||
"requires": {
|
||||
"agent-base": "6",
|
||||
@ -22552,7 +22499,7 @@
|
||||
}
|
||||
},
|
||||
"ip": {
|
||||
"version": "1.1.5",
|
||||
"version": "1.1.8",
|
||||
"bundled": true
|
||||
},
|
||||
"ip-regex": {
|
||||
@ -22567,7 +22514,7 @@
|
||||
}
|
||||
},
|
||||
"is-core-module": {
|
||||
"version": "2.8.1",
|
||||
"version": "2.9.0",
|
||||
"bundled": true,
|
||||
"requires": {
|
||||
"has": "^1.0.3"
|
||||
@ -22598,7 +22545,7 @@
|
||||
"bundled": true
|
||||
},
|
||||
"just-diff": {
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2",
|
||||
"bundled": true
|
||||
},
|
||||
"just-diff-apply": {
|
||||
@ -22717,11 +22664,11 @@
|
||||
}
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "7.8.1",
|
||||
"version": "7.9.0",
|
||||
"bundled": true
|
||||
},
|
||||
"make-fetch-happen": {
|
||||
"version": "10.1.2",
|
||||
"version": "10.1.3",
|
||||
"bundled": true,
|
||||
"requires": {
|
||||
"agentkeepalive": "^4.2.1",
|
||||
@ -22932,7 +22879,7 @@
|
||||
}
|
||||
},
|
||||
"npm-packlist": {
|
||||
"version": "5.0.2",
|
||||
"version": "5.0.3",
|
||||
"bundled": true,
|
||||
"requires": {
|
||||
"glob": "^8.0.1",
|
||||
@ -23213,12 +23160,12 @@
|
||||
}
|
||||
},
|
||||
"socks-proxy-agent": {
|
||||
"version": "6.1.1",
|
||||
"version": "6.2.0",
|
||||
"bundled": true,
|
||||
"requires": {
|
||||
"agent-base": "^6.0.2",
|
||||
"debug": "^4.3.1",
|
||||
"socks": "^2.6.1"
|
||||
"debug": "^4.3.3",
|
||||
"socks": "^2.6.2"
|
||||
}
|
||||
},
|
||||
"spdx-correct": {
|
||||
@ -25367,9 +25314,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"undici": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.1.1.tgz",
|
||||
"integrity": "sha512-CmK9JzLSMGx+2msOao8LhkKn3J7eKo2M50v0KZQ2XbiHcGqLS1HiIj01ceIm3jbUYlspw/FTSb6nMdSNyvVyaQ=="
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.2.0.tgz",
|
||||
"integrity": "sha512-XY6+NS3WH9b3TKOHeNz2CjR+qrVz/k4fO9g3etPpLozRvULoQmZ1+dk9JbIz40ehn27xzFk4jYVU2MU3Nle62A=="
|
||||
},
|
||||
"unique-filename": {
|
||||
"version": "1.1.1",
|
||||
@ -25762,11 +25709,6 @@
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
||||
"dev": true
|
||||
},
|
||||
"zod": {
|
||||
"version": "3.14.2",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.14.2.tgz",
|
||||
"integrity": "sha512-iF+wrtzz7fQfkmn60PG6XFxaWBhYYKzp2i+nv24WbLUWb2JjymdkHlzBwP0erpc78WotwP5g9AAu7Sk8GWVVNw=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
15
package.json
15
package.json
@ -1,11 +1,12 @@
|
||||
{
|
||||
"name": "discord.js-selfbot-v13",
|
||||
"version": "1.4.31",
|
||||
"version": "2.0.0",
|
||||
"description": "A unofficial discord.js fork for creating selfbots [Based on discord.js v13]",
|
||||
"main": "./src/index.js",
|
||||
"types": "./typings/index.d.ts",
|
||||
"scripts": {
|
||||
"test": "npm run lint:all && npm run lint:typings && npm run docs:test",
|
||||
"fix:all": "npm run lint:fix && npm run lint:typings:fix && npm run format",
|
||||
"test:typescript": "tsc --noEmit && tsd",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix",
|
||||
@ -62,21 +63,21 @@
|
||||
"bufferutil": "^4.0.6",
|
||||
"chalk": "^4.1.2",
|
||||
"discord-api-types": "^0.32.0",
|
||||
"discord-bettermarkdown": "^1.1.0",
|
||||
"discord-bettermarkdown": "^1.2.0",
|
||||
"discord-rpc-contructor": "^1.1.5",
|
||||
"discord.js": "^13.6.0",
|
||||
"discord.js": "^13.7.0",
|
||||
"form-data": "^4.0.0",
|
||||
"i": "^0.3.7",
|
||||
"json-bigint": "^1.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash.snakecase": "^4.1.1",
|
||||
"node-fetch": "^2.6.1",
|
||||
"npm": "^8.8.0",
|
||||
"npm": "^8.10.0",
|
||||
"qrcode-terminal": "^0.12.0",
|
||||
"safe-base64": "^2.0.1-0",
|
||||
"string_decoder": "^1.3.0",
|
||||
"string-similarity": "^4.0.4",
|
||||
"undici": "^5.1.1",
|
||||
"undici": "^5.2.0",
|
||||
"utf-8-validate": "^5.0.9",
|
||||
"ws": "^8.5.0"
|
||||
},
|
||||
@ -92,13 +93,13 @@
|
||||
"@types/node": "^16.11.12",
|
||||
"conventional-changelog-cli": "^2.2.2",
|
||||
"dtslint": "^4.2.1",
|
||||
"eslint": "^8.5.0",
|
||||
"eslint": "^8.15.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-import": "^2.25.3",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"husky": "^7.0.4",
|
||||
"is-ci": "^3.0.1",
|
||||
"jest": "^28.0.1",
|
||||
"jest": "^28.1.0",
|
||||
"lint-staged": "^12.1.4",
|
||||
"prettier": "^2.5.1",
|
||||
"tsd": "^0.20.0",
|
||||
|
@ -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,8 +18,8 @@ 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:
|
||||
@ -41,6 +42,7 @@ 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 +61,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,
|
||||
|
@ -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 };
|
||||
}
|
||||
|
@ -171,6 +171,18 @@ const Messages = {
|
||||
MESSAGE_EMBED_LINK_LENGTH: 'Message content with embed link length is too long',
|
||||
GUILD_MEMBERS_FETCH: msg => `${msg}`,
|
||||
USER_NOT_STREAMING: 'User is not streaming',
|
||||
// Djs v13.7
|
||||
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',
|
||||
|
||||
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}.`,
|
||||
};
|
||||
|
||||
for (const [name, message] of Object.entries(Messages)) register(name, message);
|
||||
|
@ -124,6 +124,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');
|
||||
@ -142,6 +144,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');
|
||||
|
@ -65,6 +65,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
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -83,10 +85,10 @@ 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 } = {}) {
|
||||
// Change from user.createDM to opcode (risky action)
|
||||
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);
|
||||
@ -97,7 +99,15 @@ class ApplicationCommandManager extends CachedManager {
|
||||
return this._add(command, cache);
|
||||
}
|
||||
await this.user.createDM().catch(() => {});
|
||||
const data = await this.commandPath({ guildId }).get();
|
||||
const data = await this.commandPath({ guildId }).get({
|
||||
headers: {
|
||||
'X-Discord-Locale': locale,
|
||||
},
|
||||
query:
|
||||
typeof withLocalizations === 'boolean'
|
||||
? new URLSearchParams({ with_localizations: withLocalizations })
|
||||
: undefined,
|
||||
});
|
||||
return data.reduce((coll, command) => coll.set(command.id, this._add(command, cache, guildId)), new Collection());
|
||||
}
|
||||
|
||||
@ -213,7 +223,9 @@ class ApplicationCommandManager extends CachedManager {
|
||||
static transformCommand(command) {
|
||||
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,
|
||||
|
@ -54,9 +54,12 @@ class GuildBanManager extends CachedManager {
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options used to fetch all bans from a guild.
|
||||
* Options used to fetch multiple bans from a guild.
|
||||
* @typedef {Object} FetchBansOptions
|
||||
* @property {boolean} cache Whether or not to cache the fetched bans
|
||||
* @property {number} [limit] The maximum number of bans to return
|
||||
* @property {Snowflake} [before] Consider only bans before this id
|
||||
* @property {Snowflake} [after] Consider only bans after this id
|
||||
* @property {boolean} [cache] Whether to cache the fetched bans
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -64,13 +67,13 @@ class GuildBanManager extends CachedManager {
|
||||
* @param {UserResolvable|FetchBanOptions|FetchBansOptions} [options] Options for fetching guild ban(s)
|
||||
* @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 +94,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,11 +115,13 @@ 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
|
||||
|
@ -4,11 +4,15 @@ 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 { ThreadChannelTypes, ChannelTypes, VideoQualityModes } = require('../util/Constants');
|
||||
const DataResolver = require('../util/DataResolver');
|
||||
const Util = require('../util/Util');
|
||||
const { resolveAutoArchiveMaxLimit } = require('../util/Util');
|
||||
|
||||
let cacheWarningEmitted = false;
|
||||
let storeChannelDeprecationEmitted = false;
|
||||
@ -169,6 +173,153 @@ class GuildChannelManager extends CachedManager {
|
||||
return this.client.actions.ChannelCreate.handle(data).channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a webhook for the channel.
|
||||
* @param {GuildChannelResolvable} channel The channel to create the webhook for
|
||||
* @param {string} name The name of the webhook
|
||||
* @param {ChannelWebhookCreateOptions} [options] Options for creating the webhook
|
||||
* @returns {Promise<Webhook>} Returns the created Webhook
|
||||
* @example
|
||||
* // Create a webhook for the current channel
|
||||
* guild.channels.createWebhook('222197033908436994', 'Snek', {
|
||||
* avatar: 'https://i.imgur.com/mI8XcpG.jpg',
|
||||
* reason: 'Needed a cool new Webhook'
|
||||
* })
|
||||
* .then(console.log)
|
||||
* .catch(console.error)
|
||||
*/
|
||||
async createWebhook(channel, name, { avatar, reason } = {}) {
|
||||
const id = this.resolveId(channel);
|
||||
if (!id) throw new TypeError('INVALID_TYPE', 'channel', 'GuildChannelResolvable');
|
||||
if (typeof avatar === 'string' && !avatar.startsWith('data:')) {
|
||||
avatar = await DataResolver.resolveImage(avatar);
|
||||
}
|
||||
const data = await this.client.api.channels[id].webhooks.post({
|
||||
data: {
|
||||
name,
|
||||
avatar,
|
||||
},
|
||||
reason,
|
||||
});
|
||||
return new Webhook(this.client, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* The data for a guild channel.
|
||||
* @typedef {Object} ChannelData
|
||||
* @property {string} [name] The name of the channel
|
||||
* @property {ChannelType} [type] The type of the channel (only conversion between text and news is supported)
|
||||
* @property {number} [position] The position of the channel
|
||||
* @property {string} [topic] The topic of the text channel
|
||||
* @property {boolean} [nsfw] Whether the channel is NSFW
|
||||
* @property {number} [bitrate] The bitrate of the voice channel
|
||||
* @property {number} [userLimit] The user limit of the voice channel
|
||||
* @property {?CategoryChannelResolvable} [parent] The parent of the channel
|
||||
* @property {boolean} [lockPermissions]
|
||||
* Lock the permissions of the channel to what the parent's permissions are
|
||||
* @property {OverwriteResolvable[]|Collection<Snowflake, OverwriteResolvable>} [permissionOverwrites]
|
||||
* Permission overwrites for the channel
|
||||
* @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the channel in seconds
|
||||
* @property {ThreadAutoArchiveDuration} [defaultAutoArchiveDuration]
|
||||
* The default auto archive duration for all new threads in this channel
|
||||
* @property {?string} [rtcRegion] The RTC region of the channel
|
||||
* @property {?VideoQualityMode|number} [videoQualityMode] The camera video quality mode of the channel
|
||||
*/
|
||||
|
||||
/**
|
||||
* Edits the channel.
|
||||
* @param {GuildChannelResolvable} channel The channel to edit
|
||||
* @param {ChannelData} data The new data for the channel
|
||||
* @param {string} [reason] Reason for editing this channel
|
||||
* @returns {Promise<GuildChannel>}
|
||||
* @example
|
||||
* // Edit a channel
|
||||
* guild.channels.edit('222197033908436994', { name: 'new-channel' })
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async edit(channel, data, reason) {
|
||||
channel = this.resolve(channel);
|
||||
if (!channel) throw new TypeError('INVALID_TYPE', 'channel', 'GuildChannelResolvable');
|
||||
|
||||
const parent = data.parent && this.client.channels.resolveId(data.parent);
|
||||
|
||||
if (typeof data.position !== 'undefined') await this.setPosition(channel, data.position, { reason });
|
||||
|
||||
let permission_overwrites = data.permissionOverwrites?.map(o => PermissionOverwrites.resolve(o, this.guild));
|
||||
|
||||
if (data.lockPermissions) {
|
||||
if (parent) {
|
||||
const newParent = this.guild.channels.resolve(parent);
|
||||
if (newParent?.type === 'GUILD_CATEGORY') {
|
||||
permission_overwrites = newParent.permissionOverwrites.cache.map(o =>
|
||||
PermissionOverwrites.resolve(o, this.guild),
|
||||
);
|
||||
}
|
||||
} else if (channel.parent) {
|
||||
permission_overwrites = this.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: data.rtcRegion ?? channel.rtcRegion,
|
||||
video_quality_mode:
|
||||
typeof data.videoQualityMode === 'string' ? VideoQualityModes[data.videoQualityMode] : data.videoQualityMode,
|
||||
parent_id: parent,
|
||||
lock_permissions: data.lockPermissions,
|
||||
rate_limit_per_user: data.rateLimitPerUser,
|
||||
default_auto_archive_duration: defaultAutoArchiveDuration,
|
||||
permission_overwrites,
|
||||
},
|
||||
reason,
|
||||
});
|
||||
|
||||
return this.client.actions.ChannelUpdate.handle(newData).updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new position for the guild channel.
|
||||
* @param {GuildChannelResolvable} channel The channel to set the position for
|
||||
* @param {number} position The new position for the guild channel
|
||||
* @param {SetChannelPositionOptions} [options] Options for setting position
|
||||
* @returns {Promise<GuildChannel>}
|
||||
* @example
|
||||
* // Set a new channel position
|
||||
* guild.channels.setPosition('222078374472843266', 2)
|
||||
* .then(newChannel => console.log(`Channel's new position is ${newChannel.position}`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async setPosition(channel, position, { relative, reason } = {}) {
|
||||
channel = this.resolve(channel);
|
||||
if (!channel) throw new TypeError('INVALID_TYPE', 'channel', 'GuildChannelResolvable');
|
||||
const updatedChannels = await Util.setPosition(
|
||||
channel,
|
||||
position,
|
||||
relative,
|
||||
this.guild._sortedChannels(this),
|
||||
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
|
||||
@ -204,6 +355,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>
|
||||
@ -243,6 +427,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;
|
||||
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;
|
||||
|
@ -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) {
|
||||
|
@ -353,7 +353,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,7 +376,7 @@ 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 }) {
|
||||
@ -387,7 +387,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')
|
||||
|
@ -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,
|
||||
@ -268,7 +275,7 @@ class GuildScheduledEventManager extends CachedManager {
|
||||
const guildScheduledEventId = this.resolveId(guildScheduledEvent);
|
||||
if (!guildScheduledEventId) throw new Error('GUILD_SCHEDULED_EVENT_RESOLVE');
|
||||
|
||||
const { limit, withMember, before, after } = options;
|
||||
let { limit, withMember, before, after } = options;
|
||||
|
||||
const data = await this.client.api.guilds(this.guild.id, 'scheduled-events', guildScheduledEventId).users.get({
|
||||
query: { limit, with_member: withMember, before, after },
|
||||
|
@ -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.guildId).stickers(sticker.id).get();
|
||||
sticker._patch(data);
|
||||
return sticker.user;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GuildStickerManager;
|
||||
|
@ -158,25 +158,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 });
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -5,6 +5,7 @@ const CachedManager = require('./CachedManager');
|
||||
const { TypeError } = require('../errors');
|
||||
const ThreadChannel = require('../structures/ThreadChannel');
|
||||
const { ChannelTypes } = require('../util/Constants');
|
||||
const { resolveAutoArchiveMaxLimit } = require('../util/Util');
|
||||
|
||||
/**
|
||||
* Manages API methods for {@link ThreadChannel} objects and stores their cache.
|
||||
@ -120,14 +121,8 @@ class ThreadManager extends CachedManager {
|
||||
} else if (this.channel.type !== 'GUILD_NEWS') {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (autoArchiveDuration === 'MAX') autoArchiveDuration = resolveAutoArchiveMaxLimit(this.channel.guild);
|
||||
|
||||
const data = await path.threads.post({
|
||||
data: {
|
||||
|
@ -29,11 +29,16 @@ class RESTManager {
|
||||
}
|
||||
|
||||
getAuth() {
|
||||
if (this.client.token && this.client.user && this.client.user.bot) {
|
||||
if ((this.client.token && this.client.user && this.client.user.bot) || this.client.accessToken) {
|
||||
return `Bot ${this.client.token}`;
|
||||
} else if (this.client.token) {
|
||||
return this.client.token;
|
||||
}
|
||||
/*
|
||||
// v13.7
|
||||
const token = this.client.token ?? this.client.accessToken;
|
||||
if (token) return `Bot ${token}`;
|
||||
*/
|
||||
throw new Error('TOKEN_MISSING');
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,6 +65,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
|
||||
@ -73,6 +93,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
|
||||
@ -131,7 +171,9 @@ 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
|
||||
@ -146,10 +188,12 @@ 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
|
||||
@ -157,6 +201,13 @@ class ApplicationCommand extends Base {
|
||||
* @property {number} [maxValue] The maximum value for an `INTEGER` or `NUMBER` option
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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
|
||||
@ -182,6 +233,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
|
||||
@ -191,6 +259,23 @@ 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 });
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits the default permission of this ApplicationCommand
|
||||
* @param {boolean} [defaultPermission=true] The default permission for this command
|
||||
@ -349,7 +434,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
|
||||
@ -364,12 +453,14 @@ class ApplicationCommand extends Base {
|
||||
* 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
|
||||
@ -379,14 +470,27 @@ class ApplicationCommand extends Base {
|
||||
const channelTypesKey = received ? 'channelTypes' : 'channel_types';
|
||||
const minValueKey = received ? 'minValue' : 'min_value';
|
||||
const maxValueKey = received ? 'maxValue' : 'max_value';
|
||||
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])
|
||||
|
@ -76,7 +76,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 MessageManager = require('../managers/MessageManager');
|
||||
const ThreadManager = require('../managers/ThreadManager');
|
||||
const DataResolver = require('../util/DataResolver');
|
||||
|
||||
/**
|
||||
* Represents a text-based guild channel on Discord.
|
||||
@ -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;
|
||||
}
|
||||
@ -121,11 +118,8 @@ class BaseGuildTextChannel extends GuildChannel {
|
||||
* .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;
|
||||
fetchWebhooks() {
|
||||
return this.guild.channels.fetchWebhooks(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -149,18 +143,8 @@ class BaseGuildTextChannel extends GuildChannel {
|
||||
* .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);
|
||||
createWebhook(name, options = {}) {
|
||||
return this.guild.channels.createWebhook(this.id, name, options);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -178,6 +162,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
|
||||
|
@ -82,17 +82,18 @@ class BaseGuildVoiceChannel extends GuildChannel {
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -10,6 +10,7 @@ let StoreChannel;
|
||||
let TextChannel;
|
||||
let ThreadChannel;
|
||||
let VoiceChannel;
|
||||
let DirectoryChannel;
|
||||
const { ChannelTypes, ThreadChannelTypes, VoiceBasedChannelTypes } = require('../util/Constants');
|
||||
const SnowflakeUtil = require('../util/SnowflakeUtil');
|
||||
// Const { ApplicationCommand } = require('discord.js-selfbot-v13'); - Not being used in this file, not necessary.
|
||||
@ -165,6 +166,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');
|
||||
@ -174,6 +183,7 @@ class Channel extends Base {
|
||||
TextChannel ??= require('./TextChannel');
|
||||
ThreadChannel ??= require('./ThreadChannel');
|
||||
VoiceChannel ??= require('./VoiceChannel');
|
||||
DirectoryChannel ??= require('./DirectoryChannel');
|
||||
|
||||
let channel;
|
||||
if (!data.guild_id && !guild) {
|
||||
@ -219,6 +229,9 @@ 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;
|
||||
}
|
||||
if (channel && !allowUnknownGuild) guild.channels?.cache.set(channel.id, channel);
|
||||
}
|
||||
|
@ -3,7 +3,15 @@
|
||||
const Team = require('./Team');
|
||||
const Application = require('./interfaces/Application');
|
||||
const { Error } = require('../errors/DJSError');
|
||||
const ApplicationCommandManager = require('../managers/ApplicationCommandManager');
|
||||
const ApplicationFlags = require('../util/ApplicationFlags');
|
||||
const Permissions = require('../util/Permissions');
|
||||
|
||||
/**
|
||||
* @typedef {Object} ClientApplicationInstallParams
|
||||
* @property {InviteScope[]} scopes The scopes to add the application to the server with
|
||||
* @property {Readonly<Permissions>} permissions The permissions this bot will request upon joining
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a Client OAuth2 Application.
|
||||
@ -17,12 +25,41 @@ class ClientApplication extends Application {
|
||||
* The application command manager for this application
|
||||
* @type {ApplicationCommandManager}
|
||||
*/
|
||||
this.commands = null; // Selfbot
|
||||
this.commands = new ApplicationCommandManager(this.client);
|
||||
}
|
||||
|
||||
_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
|
||||
|
@ -251,6 +251,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;
|
||||
|
19
src/structures/DirectoryChannel.js
Normal file
19
src/structures/DirectoryChannel.js
Normal file
@ -0,0 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
const { Channel } = require('./Channel');
|
||||
|
||||
/**
|
||||
* Represents a channel that displays a directory of guilds
|
||||
*/
|
||||
class DirectoryChannel extends Channel {
|
||||
_patch(data) {
|
||||
super._patch(data);
|
||||
/**
|
||||
* The channel's name
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = data.name;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DirectoryChannel;
|
@ -283,14 +283,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
|
||||
@ -416,8 +408,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;
|
||||
}
|
||||
@ -874,24 +866,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
|
||||
* @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
|
||||
*/
|
||||
|
||||
@ -978,7 +970,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;
|
||||
}
|
||||
@ -1058,7 +1050,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>}
|
||||
*/
|
||||
@ -1105,7 +1097,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
|
||||
@ -1120,7 +1112,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
|
||||
@ -1135,7 +1127,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
|
||||
@ -1240,7 +1232,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
|
||||
@ -1296,7 +1288,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
|
||||
@ -1311,7 +1303,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
|
||||
|
@ -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:
|
||||
@ -262,27 +260,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 +271,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 +336,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
|
||||
@ -544,7 +445,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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -300,7 +300,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.me?.permissions.has(Permissions.FLAGS.MODERATE_MEMBERS) ?? false)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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 {
|
||||
|
@ -75,16 +75,51 @@ class Interaction extends Base {
|
||||
*/
|
||||
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 {string}
|
||||
* @see {@link https://discord.com/developers/docs/dispatch/field-values#predefined-field-values-accepted-locales}
|
||||
* @type {Locale}
|
||||
*/
|
||||
this.locale = data.locale;
|
||||
|
||||
/**
|
||||
* The preferred locale from the guild this interaction was sent in
|
||||
* @type {?string}
|
||||
* @type {?Locale}
|
||||
*/
|
||||
this.guildLocale = data.guild_locale ?? null;
|
||||
}
|
||||
@ -173,6 +208,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}
|
||||
@ -226,6 +269,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) {
|
||||
/**
|
||||
|
@ -725,6 +725,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
|
||||
@ -732,14 +733,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
|
||||
@ -747,9 +749,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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -209,7 +209,7 @@ class MessageEmbed {
|
||||
this.provider = data.provider
|
||||
? {
|
||||
name: data.provider.name,
|
||||
url: data.provider.name,
|
||||
url: data.provider.url,
|
||||
}
|
||||
: null;
|
||||
|
||||
@ -430,7 +430,7 @@ class MessageEmbed {
|
||||
*/
|
||||
setFooter(options, deprecatedIconURL) {
|
||||
if (options === null) {
|
||||
this.footer = {};
|
||||
this.footer = undefined;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -173,28 +173,35 @@ class MessageMentions {
|
||||
* @typedef {Object} MessageMentionsHasOptions
|
||||
* @property {boolean} [ignoreDirect=false] Whether to ignore direct mentions to the item
|
||||
* @property {boolean} [ignoreRoles=false] Whether to ignore role mentions to a guild member
|
||||
* @property {boolean} [ignoreEveryone=false] Whether to ignore everyone/here mentions
|
||||
* @property {boolean} [ignoreRepliedUser=false] Whether to ignore replied user mention to an user
|
||||
* @property {boolean} [ignoreEveryone=false] Whether to ignore `@everyone`/`@here` mentions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Checks if a user, guild member, role, or channel is mentioned.
|
||||
* Takes into account user mentions, role mentions, and `@everyone`/`@here` mentions.
|
||||
* Checks if a user, guild member, thread member, role, or channel is mentioned.
|
||||
* Takes into account user mentions, role mentions, channel mentions,
|
||||
* replied user mention, and `@everyone`/`@here` mentions.
|
||||
* @param {UserResolvable|RoleResolvable|ChannelResolvable} data The User/Role/Channel to check for
|
||||
* @param {MessageMentionsHasOptions} [options] The options for the check
|
||||
* @returns {boolean}
|
||||
*/
|
||||
has(data, { ignoreDirect = false, ignoreRoles = false, ignoreEveryone = false } = {}) {
|
||||
if (!ignoreEveryone && this.everyone) return true;
|
||||
const { GuildMember } = require('./GuildMember');
|
||||
if (!ignoreRoles && data instanceof GuildMember) {
|
||||
for (const role of this.roles.values()) if (data.roles.cache.has(role.id)) return true;
|
||||
}
|
||||
has(data, { ignoreDirect = false, ignoreRoles = false, ignoreRepliedUser = false, ignoreEveryone = false } = {}) {
|
||||
const user = this.client.users.resolve(data);
|
||||
const role = this.guild?.roles.resolve(data);
|
||||
const channel = this.client.channels.resolve(data);
|
||||
|
||||
if (!ignoreRepliedUser && this.users.has(this.repliedUser?.id) && this.repliedUser?.id === user?.id) return true;
|
||||
if (!ignoreDirect) {
|
||||
const id =
|
||||
this.guild?.roles.resolveId(data) ?? this.client.channels.resolveId(data) ?? this.client.users.resolveId(data);
|
||||
|
||||
return typeof id === 'string' && (this.users.has(id) || this.channels.has(id) || this.roles.has(id));
|
||||
if (this.users.has(user?.id)) return true;
|
||||
if (this.roles.has(role?.id)) return true;
|
||||
if (this.channels.has(channel?.id)) return true;
|
||||
}
|
||||
if (user && !ignoreEveryone && this.everyone) return true;
|
||||
if (!ignoreRoles) {
|
||||
const member = this.guild?.members.resolve(data);
|
||||
if (member) {
|
||||
for (const mentionedRole of this.roles.values()) if (member.roles.cache.has(mentionedRole.id)) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -149,11 +149,17 @@ class MessagePayload {
|
||||
}
|
||||
|
||||
let flags;
|
||||
if (this.isMessage || this.isMessageManager) {
|
||||
if (
|
||||
typeof this.options.flags !== 'undefined' ||
|
||||
(this.isMessage && typeof this.options.reply === 'undefined') ||
|
||||
this.isMessageManager
|
||||
) {
|
||||
// eslint-disable-next-line eqeqeq
|
||||
flags = this.options.flags != null ? new MessageFlags(this.options.flags).bitfield : this.target.flags?.bitfield;
|
||||
} else if (isInteraction && this.options.ephemeral) {
|
||||
flags = MessageFlags.FLAGS.EPHEMERAL;
|
||||
}
|
||||
|
||||
if (isInteraction && this.options.ephemeral) {
|
||||
flags |= MessageFlags.FLAGS.EPHEMERAL;
|
||||
}
|
||||
|
||||
let allowedMentions =
|
||||
|
@ -114,7 +114,7 @@ class MessageReaction {
|
||||
if (this.partial) return;
|
||||
this.users.cache.set(user.id, user);
|
||||
if (!this.me || user.id !== this.message.client.user.id || this.count === 0) this.count++;
|
||||
this.me ??= user.id === this.message.client.user.id;
|
||||
this.me ||= user.id === this.message.client.user.id;
|
||||
}
|
||||
|
||||
_remove(user) {
|
||||
|
103
src/structures/Modal.js
Normal file
103
src/structures/Modal.js
Normal file
@ -0,0 +1,103 @@
|
||||
'use strict';
|
||||
|
||||
const BaseMessageComponent = require('./BaseMessageComponent');
|
||||
const Util = require('../util/Util');
|
||||
|
||||
/**
|
||||
* Represents a modal (form) to be shown in response to an interaction
|
||||
*/
|
||||
class Modal {
|
||||
/**
|
||||
* @typedef {Object} ModalOptions
|
||||
* @property {string} [customId] A unique string to be sent in the interaction when clicked
|
||||
* @property {string} [title] The title to be displayed on this modal
|
||||
* @property {MessageActionRow[]|MessageActionRowOptions[]} [components]
|
||||
* Action rows containing interactive components for the modal (text input components)
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {Modal|ModalOptions} data Modal to clone or raw data
|
||||
* @param {Client} client The client constructing this Modal, if provided
|
||||
*/
|
||||
constructor(data = {}, client = null) {
|
||||
/**
|
||||
* A list of MessageActionRows in the modal
|
||||
* @type {MessageActionRow[]}
|
||||
*/
|
||||
this.components = data.components?.map(c => BaseMessageComponent.create(c, client)) ?? [];
|
||||
|
||||
/**
|
||||
* A unique string to be sent in the interaction when submitted
|
||||
* @type {?string}
|
||||
*/
|
||||
this.customId = data.custom_id ?? data.customId ?? null;
|
||||
|
||||
/**
|
||||
* The title to be displayed on this modal
|
||||
* @type {?string}
|
||||
*/
|
||||
this.title = data.title ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds components to the modal.
|
||||
* @param {...MessageActionRowResolvable[]} components The components to add
|
||||
* @returns {Modal}
|
||||
*/
|
||||
addComponents(...components) {
|
||||
this.components.push(...components.flat(Infinity).map(c => BaseMessageComponent.create(c)));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the components of the modal.
|
||||
* @param {...MessageActionRowResolvable[]} components The components to set
|
||||
* @returns {Modal}
|
||||
*/
|
||||
setComponents(...components) {
|
||||
this.spliceComponents(0, this.components.length, components);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the custom id for this modal
|
||||
* @param {string} customId A unique string to be sent in the interaction when submitted
|
||||
* @returns {Modal}
|
||||
*/
|
||||
setCustomId(customId) {
|
||||
this.customId = Util.verifyString(customId, RangeError, 'MODAL_CUSTOM_ID');
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes, replaces, and inserts components in the modal.
|
||||
* @param {number} index The index to start at
|
||||
* @param {number} deleteCount The number of components to remove
|
||||
* @param {...MessageActionRowResolvable[]} [components] The replacing components
|
||||
* @returns {Modal}
|
||||
*/
|
||||
spliceComponents(index, deleteCount, ...components) {
|
||||
this.components.splice(index, deleteCount, ...components.flat(Infinity).map(c => BaseMessageComponent.create(c)));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the title of this modal
|
||||
* @param {string} title The title to be displayed on this modal
|
||||
* @returns {Modal}
|
||||
*/
|
||||
setTitle(title) {
|
||||
this.title = Util.verifyString(title, RangeError, 'MODAL_TITLE');
|
||||
return this;
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
components: this.components.map(c => c.toJSON()),
|
||||
custom_id: this.customId,
|
||||
title: this.title,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Modal;
|
53
src/structures/ModalSubmitFieldsResolver.js
Normal file
53
src/structures/ModalSubmitFieldsResolver.js
Normal file
@ -0,0 +1,53 @@
|
||||
'use strict';
|
||||
|
||||
const { TypeError } = require('../errors');
|
||||
const { MessageComponentTypes } = require('../util/Constants');
|
||||
|
||||
/**
|
||||
* A resolver for modal submit interaction text inputs.
|
||||
*/
|
||||
class ModalSubmitFieldsResolver {
|
||||
constructor(components) {
|
||||
/**
|
||||
* The components within the modal
|
||||
* @type {PartialModalActionRow[]} The components in the modal
|
||||
*/
|
||||
this.components = components;
|
||||
}
|
||||
|
||||
/**
|
||||
* The extracted fields from the modal
|
||||
* @type {PartialInputTextData[]} The fields in the modal
|
||||
* @private
|
||||
*/
|
||||
get _fields() {
|
||||
return this.components.reduce((previous, next) => previous.concat(next.components), []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a field given a custom id from a component
|
||||
* @param {string} customId The custom id of the component
|
||||
* @returns {?PartialInputTextData}
|
||||
*/
|
||||
getField(customId) {
|
||||
const field = this._fields.find(f => f.customId === customId);
|
||||
if (!field) throw new TypeError('MODAL_SUBMIT_INTERACTION_FIELD_NOT_FOUND', customId);
|
||||
return field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of a text input component given a custom id
|
||||
* @param {string} customId The custom id of the text input component
|
||||
* @returns {?string}
|
||||
*/
|
||||
getTextInputValue(customId) {
|
||||
const field = this.getField(customId);
|
||||
const expectedType = MessageComponentTypes[MessageComponentTypes.TEXT_INPUT];
|
||||
if (field.type !== expectedType) {
|
||||
throw new TypeError('MODAL_SUBMIT_INTERACTION_FIELD_TYPE', customId, field.type, expectedType);
|
||||
}
|
||||
return field.value;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ModalSubmitFieldsResolver;
|
111
src/structures/ModalSubmitInteraction.js
Normal file
111
src/structures/ModalSubmitInteraction.js
Normal file
@ -0,0 +1,111 @@
|
||||
'use strict';
|
||||
|
||||
const Interaction = require('./Interaction');
|
||||
const InteractionWebhook = require('./InteractionWebhook');
|
||||
const ModalSubmitFieldsResolver = require('./ModalSubmitFieldsResolver');
|
||||
const InteractionResponses = require('./interfaces/InteractionResponses');
|
||||
const { MessageComponentTypes } = require('../util/Constants');
|
||||
|
||||
/**
|
||||
* Represents a modal submit interaction.
|
||||
* @extends {Interaction}
|
||||
* @implements {InteractionResponses}
|
||||
*/
|
||||
class ModalSubmitInteraction extends Interaction {
|
||||
constructor(client, data) {
|
||||
super(client, data);
|
||||
|
||||
/**
|
||||
* The custom id of the modal.
|
||||
* @type {string}
|
||||
*/
|
||||
this.customId = data.data.custom_id;
|
||||
|
||||
/**
|
||||
* @typedef {Object} PartialTextInputData
|
||||
* @property {string} [customId] A unique string to be sent in the interaction when submitted
|
||||
* @property {MessageComponentType} [type] The type of this component
|
||||
* @property {string} [value] Value of this text input component
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} PartialModalActionRow
|
||||
* @property {MessageComponentType} [type] The type of this component
|
||||
* @property {PartialTextInputData[]} [components] Partial text input components
|
||||
*/
|
||||
|
||||
/**
|
||||
* The inputs within the modal
|
||||
* @type {PartialModalActionRow[]}
|
||||
*/
|
||||
this.components =
|
||||
data.data.components?.map(c => ({
|
||||
type: MessageComponentTypes[c.type],
|
||||
components: ModalSubmitInteraction.transformComponent(c),
|
||||
})) ?? [];
|
||||
|
||||
/**
|
||||
* The message associated with this interaction
|
||||
* @type {Message|APIMessage|null}
|
||||
*/
|
||||
this.message = data.message ? this.channel?.messages._add(data.message) ?? data.message : null;
|
||||
|
||||
/**
|
||||
* The fields within the modal
|
||||
* @type {ModalSubmitFieldsResolver}
|
||||
*/
|
||||
this.fields = new ModalSubmitFieldsResolver(this.components);
|
||||
|
||||
/**
|
||||
* Whether the reply to this interaction has been deferred
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.deferred = false;
|
||||
|
||||
/**
|
||||
* Whether the reply to this interaction is ephemeral
|
||||
* @type {?boolean}
|
||||
*/
|
||||
this.ephemeral = null;
|
||||
|
||||
/**
|
||||
* Whether this interaction has already been replied to
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.replied = false;
|
||||
|
||||
/**
|
||||
* An associated interaction webhook, can be used to further interact with this interaction
|
||||
* @type {InteractionWebhook}
|
||||
*/
|
||||
this.webhook = new InteractionWebhook(this.client, this.applicationId, this.token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms component data to discord.js-compatible data
|
||||
* @param {*} rawComponent The data to transform
|
||||
* @returns {PartialTextInputData[]}
|
||||
*/
|
||||
static transformComponent(rawComponent) {
|
||||
return rawComponent.components.map(c => ({
|
||||
value: c.value,
|
||||
type: MessageComponentTypes[c.type],
|
||||
customId: c.custom_id,
|
||||
}));
|
||||
}
|
||||
|
||||
// These are here only for documentation purposes - they are implemented by InteractionResponses
|
||||
/* eslint-disable no-empty-function */
|
||||
deferReply() {}
|
||||
reply() {}
|
||||
fetchReply() {}
|
||||
editReply() {}
|
||||
deleteReply() {}
|
||||
followUp() {}
|
||||
update() {}
|
||||
deferUpdate() {}
|
||||
}
|
||||
|
||||
InteractionResponses.applyToClass(ModalSubmitInteraction, ['showModal', 'awaitModalSubmit']);
|
||||
|
||||
module.exports = ModalSubmitInteraction;
|
@ -351,13 +351,21 @@ class RichPresenceAssets {
|
||||
* @returns {?string}
|
||||
*/
|
||||
smallImageURL({ format, size } = {}) {
|
||||
return (
|
||||
this.smallImage &&
|
||||
this.activity.presence.client.rest.cdn.AppAsset(this.activity.applicationId, this.smallImage, {
|
||||
format,
|
||||
size,
|
||||
})
|
||||
);
|
||||
if (!this.smallImage) return null;
|
||||
if (this.smallImage.includes(':')) {
|
||||
const [platform, id] = this.smallImage.split(':');
|
||||
switch (platform) {
|
||||
case 'mp':
|
||||
return `https://media.discordapp.net/${id}`;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return this.activity.presence.client.rest.cdn.AppAsset(this.activity.applicationId, this.smallImage, {
|
||||
format,
|
||||
size,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -367,11 +375,20 @@ class RichPresenceAssets {
|
||||
*/
|
||||
largeImageURL({ format, size } = {}) {
|
||||
if (!this.largeImage) return null;
|
||||
if (/^spotify:/.test(this.largeImage)) {
|
||||
return `https://i.scdn.co/image/${this.largeImage.slice(8)}`;
|
||||
} else if (/^twitch:/.test(this.largeImage)) {
|
||||
return `https://static-cdn.jtvnw.net/previews-ttv/live_user_${this.largeImage.slice(7)}.png`;
|
||||
if (this.largeImage.includes(':')) {
|
||||
const [platform, id] = this.largeImage.split(':');
|
||||
switch (platform) {
|
||||
case 'mp':
|
||||
return `https://media.discordapp.net/${id}`;
|
||||
case 'spotify':
|
||||
return `https://i.scdn.co/image/${id}`;
|
||||
case 'twitch':
|
||||
return `https://static-cdn.jtvnw.net/previews-ttv/live_user_${id}.png`;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return this.activity.presence.client.rest.cdn.AppAsset(this.activity.applicationId, this.largeImage, {
|
||||
format,
|
||||
size,
|
||||
|
@ -5,7 +5,6 @@ const Base = require('./Base');
|
||||
const { Error } = require('../errors');
|
||||
const Permissions = require('../util/Permissions');
|
||||
const SnowflakeUtil = require('../util/SnowflakeUtil');
|
||||
const Util = require('../util/Util');
|
||||
|
||||
let deprecationEmittedForComparePositions = false;
|
||||
|
||||
@ -399,20 +398,8 @@ class Role extends Base {
|
||||
* .then(updated => console.log(`Role position: ${updated.position}`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async setPosition(position, { relative, reason } = {}) {
|
||||
const updatedRoles = await Util.setPosition(
|
||||
this,
|
||||
position,
|
||||
relative,
|
||||
this.guild._sortedRoles(),
|
||||
this.client.api.guilds(this.guild.id).roles,
|
||||
reason,
|
||||
);
|
||||
this.client.actions.GuildRolesPositionUpdate.handle({
|
||||
guild_id: this.guild.id,
|
||||
roles: updatedRoles,
|
||||
});
|
||||
return this;
|
||||
setPosition(position, options = {}) {
|
||||
return this.guild.roles.setPosition(this, position, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,14 +55,15 @@ class StageChannel extends BaseGuildVoiceChannel {
|
||||
/**
|
||||
* Sets the RTC region of the channel.
|
||||
* @name StageChannel#setRTCRegion
|
||||
* @param {?string} region The new region of the channel. Set to `null` to remove a specific region for the channel
|
||||
* @param {?string} rtcRegion The new region of the channel. Set to `null` to remove a specific region for the channel
|
||||
* @param {string} [reason] The reason for modifying this region.
|
||||
* @returns {Promise<StageChannel>}
|
||||
* @example
|
||||
* // Set the RTC region to europe
|
||||
* stageChannel.setRTCRegion('europe');
|
||||
* // Set the RTC region to sydney
|
||||
* stageChannel.setRTCRegion('sydney');
|
||||
* @example
|
||||
* // Remove a fixed region for this channel - let Discord decide automatically
|
||||
* stageChannel.setRTCRegion(null);
|
||||
* stageChannel.setRTCRegion(null, 'We want to let Discord decide.');
|
||||
*/
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,16 @@ class StageInstance extends Base {
|
||||
} else {
|
||||
this.discoverableDisabled ??= null;
|
||||
}
|
||||
|
||||
if ('guild_scheduled_event_id' in data) {
|
||||
/**
|
||||
* The associated guild scheduled event id of this stage instance
|
||||
* @type {?Snowflake}
|
||||
*/
|
||||
this.guildScheduledEventId = data.guild_scheduled_event_id;
|
||||
} else {
|
||||
this.guildScheduledEventId ??= null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,6 +93,15 @@ class StageInstance extends Base {
|
||||
return this.client.channels.resolve(this.channelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* The associated guild scheduled event of this stage instance
|
||||
* @type {?GuildScheduledEvent}
|
||||
* @readonly
|
||||
*/
|
||||
get guildScheduledEvent() {
|
||||
return this.guild?.scheduledEvents.resolve(this.guildScheduledEventId) ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the stage instance has been deleted
|
||||
* @type {boolean}
|
||||
|
@ -228,10 +228,7 @@ class Sticker extends Base {
|
||||
async fetchUser() {
|
||||
if (this.partial) await this.fetch();
|
||||
if (!this.guildId) throw new Error('NOT_GUILD_STICKER');
|
||||
|
||||
const data = await this.client.api.guilds(this.guildId).stickers(this.id).get();
|
||||
this._patch(data);
|
||||
return this.user;
|
||||
return this.guild.stickers.fetchUser(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4,7 +4,7 @@ const GuildChannel = require('./GuildChannel');
|
||||
|
||||
/**
|
||||
* Represents a guild store channel on Discord.
|
||||
* <warn>Store channels are deprecated and will be removed from Discord in March 2022. See
|
||||
* <warn>Store channels have been removed from Discord. See
|
||||
* [Self-serve Game Selling Deprecation](https://support-dev.discord.com/hc/en-us/articles/4414590563479)
|
||||
* for more information.</warn>
|
||||
* @extends {GuildChannel}
|
||||
|
201
src/structures/TextInputComponent.js
Normal file
201
src/structures/TextInputComponent.js
Normal file
@ -0,0 +1,201 @@
|
||||
'use strict';
|
||||
|
||||
const BaseMessageComponent = require('./BaseMessageComponent');
|
||||
const { RangeError } = require('../errors');
|
||||
const { TextInputStyles, MessageComponentTypes } = require('../util/Constants');
|
||||
const Util = require('../util/Util');
|
||||
|
||||
/**
|
||||
* Represents a text input component in a modal
|
||||
* @extends {BaseMessageComponent}
|
||||
*/
|
||||
|
||||
class TextInputComponent extends BaseMessageComponent {
|
||||
/**
|
||||
* @typedef {BaseMessageComponentOptions} TextInputComponentOptions
|
||||
* @property {string} [customId] A unique string to be sent in the interaction when submitted
|
||||
* @property {string} [label] The text to be displayed above this text input component
|
||||
* @property {number} [maxLength] Maximum length of text that can be entered
|
||||
* @property {number} [minLength] Minimum length of text required to be entered
|
||||
* @property {string} [placeholder] Custom placeholder text to display when no text is entered
|
||||
* @property {boolean} [required] Whether or not this text input component is required
|
||||
* @property {TextInputStyleResolvable} [style] The style of this text input component
|
||||
* @property {string} [value] Value of this text input component
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {TextInputComponent|TextInputComponentOptions} [data={}] TextInputComponent to clone or raw data
|
||||
*/
|
||||
constructor(data = {}) {
|
||||
super({ type: 'TEXT_INPUT' });
|
||||
|
||||
this.setup(data);
|
||||
}
|
||||
|
||||
setup(data) {
|
||||
/**
|
||||
* A unique string to be sent in the interaction when submitted
|
||||
* @type {?string}
|
||||
*/
|
||||
this.customId = data.custom_id ?? data.customId ?? null;
|
||||
|
||||
/**
|
||||
* The text to be displayed above this text input component
|
||||
* @type {?string}
|
||||
*/
|
||||
this.label = data.label ?? null;
|
||||
|
||||
/**
|
||||
* Maximum length of text that can be entered
|
||||
* @type {?number}
|
||||
*/
|
||||
this.maxLength = data.max_length ?? data.maxLength ?? null;
|
||||
|
||||
/**
|
||||
* Minimum length of text required to be entered
|
||||
* @type {?string}
|
||||
*/
|
||||
this.minLength = data.min_length ?? data.minLength ?? null;
|
||||
|
||||
/**
|
||||
* Custom placeholder text to display when no text is entered
|
||||
* @type {?string}
|
||||
*/
|
||||
this.placeholder = data.placeholder ?? null;
|
||||
|
||||
/**
|
||||
* Whether or not this text input component is required
|
||||
* @type {?boolean}
|
||||
*/
|
||||
this.required = data.required ?? false;
|
||||
|
||||
/**
|
||||
* The style of this text input component
|
||||
* @type {?TextInputStyle}
|
||||
*/
|
||||
this.style = data.style ? TextInputComponent.resolveStyle(data.style) : null;
|
||||
|
||||
/**
|
||||
* Value of this text input component
|
||||
* @type {?string}
|
||||
*/
|
||||
this.value = data.value ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the custom id of this text input component
|
||||
* @param {string} customId A unique string to be sent in the interaction when submitted
|
||||
* @returns {TextInputComponent}
|
||||
*/
|
||||
setCustomId(customId) {
|
||||
this.customId = Util.verifyString(customId, RangeError, 'TEXT_INPUT_CUSTOM_ID');
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the label of this text input component
|
||||
* @param {string} label The text to be displayed above this text input component
|
||||
* @returns {TextInputComponent}
|
||||
*/
|
||||
setLabel(label) {
|
||||
this.label = Util.verifyString(label, RangeError, 'TEXT_INPUT_LABEL');
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text input component to be required for modal submission
|
||||
* @param {boolean} [required=true] Whether this text input component is required
|
||||
* @returns {TextInputComponent}
|
||||
*/
|
||||
setRequired(required = true) {
|
||||
this.required = required;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum length of text input required in this text input component
|
||||
* @param {number} maxLength Maximum length of text to be required
|
||||
* @returns {TextInputComponent}
|
||||
*/
|
||||
setMaxLength(maxLength) {
|
||||
this.maxLength = maxLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum length of text input required in this text input component
|
||||
* @param {number} minLength Minimum length of text to be required
|
||||
* @returns {TextInputComponent}
|
||||
*/
|
||||
setMinLength(minLength) {
|
||||
this.minLength = minLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the placeholder of this text input component
|
||||
* @param {string} placeholder Custom placeholder text to display when no text is entered
|
||||
* @returns {TextInputComponent}
|
||||
*/
|
||||
setPlaceholder(placeholder) {
|
||||
this.placeholder = Util.verifyString(placeholder, RangeError, 'TEXT_INPUT_PLACEHOLDER');
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the style of this text input component
|
||||
* @param {TextInputStyleResolvable} style The style of this text input component
|
||||
* @returns {TextInputComponent}
|
||||
*/
|
||||
setStyle(style) {
|
||||
this.style = TextInputComponent.resolveStyle(style);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of this text input component
|
||||
* @param {string} value Value of this text input component
|
||||
* @returns {TextInputComponent}
|
||||
*/
|
||||
setValue(value) {
|
||||
this.value = Util.verifyString(value, RangeError, 'TEXT_INPUT_VALUE');
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the text input component into a plain object
|
||||
* @returns {APITextInput} The raw data of this text input component
|
||||
*/
|
||||
toJSON() {
|
||||
return {
|
||||
custom_id: this.customId,
|
||||
label: this.label,
|
||||
max_length: this.maxLength,
|
||||
min_length: this.minLength,
|
||||
placeholder: this.placeholder,
|
||||
required: this.required,
|
||||
style: TextInputStyles[this.style],
|
||||
type: MessageComponentTypes[this.type],
|
||||
value: this.value,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Data that can be resolved to a TextInputStyle. This can be
|
||||
* * TextInputStyle
|
||||
* * number
|
||||
* @typedef {number|TextInputStyle} TextInputStyleResolvable
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resolves the style of a text input component
|
||||
* @param {TextInputStyleResolvable} style The style to resolve
|
||||
* @returns {TextInputStyle}
|
||||
* @private
|
||||
*/
|
||||
static resolveStyle(style) {
|
||||
return typeof style === 'string' ? style : TextInputStyles[style];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TextInputComponent;
|
@ -6,6 +6,7 @@ const { RangeError } = require('../errors');
|
||||
const MessageManager = require('../managers/MessageManager');
|
||||
const ThreadMemberManager = require('../managers/ThreadMemberManager');
|
||||
const Permissions = require('../util/Permissions');
|
||||
const { resolveAutoArchiveMaxLimit } = require('../util/Util');
|
||||
|
||||
/**
|
||||
* Represents a thread channel on Discord.
|
||||
@ -100,6 +101,11 @@ class ThreadChannel extends Channel {
|
||||
* @type {?number}
|
||||
*/
|
||||
this.archiveTimestamp = new Date(data.thread_metadata.archive_timestamp).getTime();
|
||||
|
||||
if ('create_timestamp' in data.thread_metadata) {
|
||||
// Note: this is needed because we can't assign directly to getters
|
||||
this._createdTimestamp = Date.parse(data.thread_metadata.create_timestamp);
|
||||
}
|
||||
} else {
|
||||
this.locked ??= null;
|
||||
this.archived ??= null;
|
||||
@ -108,6 +114,8 @@ class ThreadChannel extends Channel {
|
||||
this.invitable ??= null;
|
||||
}
|
||||
|
||||
this._createdTimestamp ??= this.type === 'GUILD_PRIVATE_THREAD' ? super.createdTimestamp : null;
|
||||
|
||||
if ('owner_id' in data) {
|
||||
/**
|
||||
* The id of the member who created this thread
|
||||
@ -176,6 +184,16 @@ class ThreadChannel extends Channel {
|
||||
if (data.messages) for (const message of data.messages) this.messages._add(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* The timestamp when this thread was created. This isn't available for threads
|
||||
* created before 2022-01-09
|
||||
* @type {?number}
|
||||
* @readonly
|
||||
*/
|
||||
get createdTimestamp() {
|
||||
return this._createdTimestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of associated guild member objects of this thread's members
|
||||
* @type {Collection<Snowflake, GuildMember>}
|
||||
@ -196,6 +214,15 @@ class ThreadChannel extends Channel {
|
||||
return new Date(this.archiveTimestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* The time the thread was created at
|
||||
* @type {?Date}
|
||||
* @readonly
|
||||
*/
|
||||
get createdAt() {
|
||||
return this.createdTimestamp && new Date(this.createdTimestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* The parent channel of this thread
|
||||
* @type {?(NewsChannel|TextChannel)}
|
||||
@ -288,14 +315,8 @@ class ThreadChannel extends Channel {
|
||||
*/
|
||||
async edit(data, reason) {
|
||||
let autoArchiveDuration = data.autoArchiveDuration;
|
||||
if (data.autoArchiveDuration === 'MAX') {
|
||||
autoArchiveDuration = 1440;
|
||||
if (this.guild.features.includes('SEVEN_DAY_THREAD_ARCHIVE')) {
|
||||
autoArchiveDuration = 10080;
|
||||
} else if (this.guild.features.includes('THREE_DAY_THREAD_ARCHIVE')) {
|
||||
autoArchiveDuration = 4320;
|
||||
}
|
||||
}
|
||||
if (autoArchiveDuration === 'MAX') autoArchiveDuration = resolveAutoArchiveMaxLimit(this.guild);
|
||||
|
||||
const newData = await this.client.api.channels(this.id).patch({
|
||||
data: {
|
||||
name: (data.name ?? this.name).trim(),
|
||||
@ -487,7 +508,15 @@ class ThreadChannel extends Channel {
|
||||
* @readonly
|
||||
*/
|
||||
get unarchivable() {
|
||||
return this.archived && (this.locked ? this.manageable : this.sendable);
|
||||
return this.archived && this.sendable && (!this.locked || this.manageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this thread is a private thread
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isPrivate() {
|
||||
return this.type === 'GUILD_PRIVATE_THREAD';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -501,7 +530,7 @@ class ThreadChannel 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;
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
const process = require('node:process');
|
||||
const BaseGuildVoiceChannel = require('./BaseGuildVoiceChannel');
|
||||
const { VideoQualityModes } = require('../util/Constants');
|
||||
const Permissions = require('../util/Permissions');
|
||||
|
||||
let deprecationEmittedForEditable = false;
|
||||
@ -11,6 +12,20 @@ let deprecationEmittedForEditable = false;
|
||||
* @extends {BaseGuildVoiceChannel}
|
||||
*/
|
||||
class VoiceChannel extends BaseGuildVoiceChannel {
|
||||
_patch(data) {
|
||||
super._patch(data);
|
||||
|
||||
if ('video_quality_mode' in data) {
|
||||
/**
|
||||
* The camera video quality mode of the channel.
|
||||
* @type {?VideoQualityMode}
|
||||
*/
|
||||
this.videoQualityMode = VideoQualityModes[data.videoQualityMode];
|
||||
} else {
|
||||
this.videoQualityMode ??= null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the channel is editable by the client user
|
||||
* @type {boolean}
|
||||
@ -87,17 +102,28 @@ class VoiceChannel extends BaseGuildVoiceChannel {
|
||||
return this.edit({ userLimit }, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the camera video quality mode of the channel.
|
||||
* @param {VideoQualityMode|number} videoQualityMode The new camera video quality mode.
|
||||
* @param {string} [reason] Reason for changing the camera video quality mode.
|
||||
* @returns {Promise<VoiceChannel>}
|
||||
*/
|
||||
setVideoQualityMode(videoQualityMode, reason) {
|
||||
return this.edit({ videoQualityMode }, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the RTC region of the channel.
|
||||
* @name VoiceChannel#setRTCRegion
|
||||
* @param {?string} region The new region of the channel. Set to `null` to remove a specific region for the channel
|
||||
* @param {?string} rtcRegion The new region of the channel. Set to `null` to remove a specific region for the channel
|
||||
* @param {string} [reason] The reason for modifying this region.
|
||||
* @returns {Promise<VoiceChannel>}
|
||||
* @example
|
||||
* // Set the RTC region to europe
|
||||
* voiceChannel.setRTCRegion('europe');
|
||||
* // Set the RTC region to sydney
|
||||
* voiceChannel.setRTCRegion('sydney');
|
||||
* @example
|
||||
* // Remove a fixed region for this channel - let Discord decide automatically
|
||||
* voiceChannel.setRTCRegion(null);
|
||||
* voiceChannel.setRTCRegion(null, 'We want to let Discord decide.');
|
||||
*/
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ class VoiceRegion {
|
||||
/**
|
||||
* Whether the region is VIP-only
|
||||
* @type {boolean}
|
||||
* @deprecated This property is no longer being sent by the API.
|
||||
*/
|
||||
this.vip = data.vip;
|
||||
|
||||
|
@ -118,7 +118,7 @@ class VoiceState extends Base {
|
||||
* The time at which the member requested to speak. This property is specific to stage channels only.
|
||||
* @type {?number}
|
||||
*/
|
||||
this.requestToSpeakTimestamp = new Date(data.request_to_speak_timestamp).getTime();
|
||||
this.requestToSpeakTimestamp = data.request_to_speak_timestamp && Date.parse(data.request_to_speak_timestamp);
|
||||
} else {
|
||||
this.requestToSpeakTimestamp ??= null;
|
||||
}
|
||||
|
@ -116,6 +116,7 @@ class Webhook {
|
||||
* @property {string} [username=this.name] Username override for the message
|
||||
* @property {string} [avatarURL] Avatar URL override for the message
|
||||
* @property {Snowflake} [threadId] The id of the thread in the channel to send to.
|
||||
* @property {MessageFlags} [flags] Which flags to set for the message. Only `SUPPRESS_EMBEDS` can be set.
|
||||
* <info>For interaction webhooks, this property is ignored</info>
|
||||
*/
|
||||
|
||||
|
@ -1,11 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
const process = require('node:process');
|
||||
const { ClientApplicationAssetTypes, Endpoints } = require('../../util/Constants');
|
||||
const SnowflakeUtil = require('../../util/SnowflakeUtil');
|
||||
const Base = require('../Base');
|
||||
|
||||
const AssetTypes = Object.keys(ClientApplicationAssetTypes);
|
||||
|
||||
let deprecationEmittedForFetchAssets = false;
|
||||
|
||||
/**
|
||||
* Represents an OAuth2 Application.
|
||||
* @abstract
|
||||
@ -13,10 +16,7 @@ const AssetTypes = Object.keys(ClientApplicationAssetTypes);
|
||||
class Application extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) {
|
||||
this._patch(data);
|
||||
}
|
||||
this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
@ -106,8 +106,18 @@ class Application extends Base {
|
||||
/**
|
||||
* Gets the application's rich presence assets.
|
||||
* @returns {Promise<Array<ApplicationAsset>>}
|
||||
* @deprecated This will be removed in the next major as it is unsupported functionality.
|
||||
*/
|
||||
async fetchAssets() {
|
||||
if (!deprecationEmittedForFetchAssets) {
|
||||
process.emitWarning(
|
||||
'Application#fetchAssets is deprecated as it is unsupported and will be removed in the next major version.',
|
||||
'DeprecationWarning',
|
||||
);
|
||||
|
||||
deprecationEmittedForFetchAssets = true;
|
||||
}
|
||||
|
||||
const assets = await this.client.api.oauth2.applications(this.id).assets.get();
|
||||
return assets.map(a => ({
|
||||
id: a.id,
|
||||
|
@ -1,9 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
const { Error } = require('../../errors');
|
||||
const { InteractionResponseTypes } = require('../../util/Constants');
|
||||
const { InteractionResponseTypes, InteractionTypes } = require('../../util/Constants');
|
||||
const MessageFlags = require('../../util/MessageFlags');
|
||||
const InteractionCollector = require('../InteractionCollector');
|
||||
const MessagePayload = require('../MessagePayload');
|
||||
const Modal = require('../Modal');
|
||||
|
||||
/**
|
||||
* Interface for classes that support shared interaction response types.
|
||||
@ -28,6 +30,8 @@ class InteractionResponses {
|
||||
* @typedef {BaseMessageOptions} InteractionReplyOptions
|
||||
* @property {boolean} [ephemeral] Whether the reply should be ephemeral
|
||||
* @property {boolean} [fetchReply] Whether to fetch the reply
|
||||
* @property {MessageFlags} [flags] Which flags to set for the message.
|
||||
* Only `SUPPRESS_EMBEDS` and `EPHEMERAL` can be set.
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -224,6 +228,56 @@ class InteractionResponses {
|
||||
return options.fetchReply ? this.fetchReply() : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a modal component
|
||||
* @param {Modal|ModalOptions} modal The modal to show
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async showModal(modal) {
|
||||
if (this.deferred || this.replied) throw new Error('INTERACTION_ALREADY_REPLIED');
|
||||
|
||||
const _modal = modal instanceof Modal ? modal : new Modal(modal);
|
||||
await this.client.api.interactions(this.id, this.token).callback.post({
|
||||
data: {
|
||||
type: InteractionResponseTypes.MODAL,
|
||||
data: _modal.toJSON(),
|
||||
},
|
||||
});
|
||||
this.replied = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* An object containing the same properties as CollectorOptions, but a few more:
|
||||
* @typedef {Object} AwaitModalSubmitOptions
|
||||
* @property {CollectorFilter} [filter] The filter applied to this collector
|
||||
* @property {number} time Time to wait for an interaction before rejecting
|
||||
*/
|
||||
|
||||
/**
|
||||
* Collects a single modal submit interaction that passes the filter.
|
||||
* The Promise will reject if the time expires.
|
||||
* @param {AwaitModalSubmitOptions} options Options to pass to the internal collector
|
||||
* @returns {Promise<ModalSubmitInteraction>}
|
||||
* @example
|
||||
* // Collect a modal submit interaction
|
||||
* const filter = (interaction) => interaction.customId === 'modal';
|
||||
* interaction.awaitModalSubmit({ filter, time: 15_000 })
|
||||
* .then(interaction => console.log(`${interaction.customId} was submitted!`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
awaitModalSubmit(options) {
|
||||
if (typeof options.time !== 'number') throw new Error('INVALID_TYPE', 'time', 'number');
|
||||
const _options = { ...options, max: 1, interactionType: InteractionTypes.MODAL_SUBMIT };
|
||||
return new Promise((resolve, reject) => {
|
||||
const collector = new InteractionCollector(this.client, _options);
|
||||
collector.once('end', (interactions, reason) => {
|
||||
const interaction = interactions.first();
|
||||
if (interaction) resolve(interaction);
|
||||
else reject(new Error('INTERACTION_COLLECTOR_ERROR', reason));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static applyToClass(structure, ignore = []) {
|
||||
const props = [
|
||||
'deferReply',
|
||||
@ -234,6 +288,8 @@ class InteractionResponses {
|
||||
'followUp',
|
||||
'deferUpdate',
|
||||
'update',
|
||||
'showModal',
|
||||
'awaitModalSubmit',
|
||||
];
|
||||
|
||||
for (const prop of props) {
|
||||
|
@ -74,6 +74,7 @@ class TextBasedChannel {
|
||||
* @typedef {BaseMessageOptions} MessageOptions
|
||||
* @property {ReplyOptions} [reply] The options for replying to a message
|
||||
* @property {StickerResolvable[]} [stickers=[]] Stickers to send in the message
|
||||
* @property {MessageFlags} [flags] Which flags to set for the message. Only `SUPPRESS_EMBEDS` can be set.
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -129,7 +130,7 @@ class TextBasedChannel {
|
||||
* channel.send({
|
||||
* files: [{
|
||||
* attachment: 'entire/path/to/file.jpg',
|
||||
* name: 'file.jpg'
|
||||
* name: 'file.jpg',
|
||||
* description: 'A description of the file'
|
||||
* }]
|
||||
* })
|
||||
@ -237,7 +238,7 @@ class TextBasedChannel {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a button interaction collector.
|
||||
* Creates a component interaction collector.
|
||||
* @param {MessageComponentCollectorOptions} [options={}] Options to send to the collector
|
||||
* @returns {InteractionCollector}
|
||||
* @example
|
||||
|
@ -156,6 +156,8 @@ exports.Endpoints = {
|
||||
`${root}/stickers/${stickerId}.${stickerFormat === 'LOTTIE' ? 'json' : 'png'}`,
|
||||
RoleIcon: (roleId, hash, format = 'webp', size) =>
|
||||
makeImageUrl(`${root}/role-icons/${roleId}/${hash}`, { size, format }),
|
||||
guildScheduledEventCover: (scheduledEventId, coverHash, format, size) =>
|
||||
makeImageUrl(`${root}/guild-events/${scheduledEventId}/${coverHash}`, { size, format }),
|
||||
};
|
||||
},
|
||||
invite: (root, code, eventId) => (eventId ? `${root}/${code}?event=${eventId}` : `${root}/${code}`),
|
||||
@ -647,6 +649,7 @@ exports.ActivityTypes = createEnum(['PLAYING', 'STREAMING', 'LISTENING', 'WATCHI
|
||||
* * `GUILD_PUBLIC_THREAD` - a guild text channel's public thread channel
|
||||
* * `GUILD_PRIVATE_THREAD` - a guild text channel's private thread channel
|
||||
* * `GUILD_STAGE_VOICE` - a guild stage voice channel
|
||||
* * `GUILD_DIRECTORY` - the channel in a hub containing guilds
|
||||
* * `UNKNOWN` - a generic channel of unknown type, could be Channel or GuildChannel
|
||||
* @typedef {string} ChannelType
|
||||
* @see {@link https://discord.com/developers/docs/resources/channel#channel-object-channel-types}
|
||||
@ -665,6 +668,7 @@ exports.ChannelTypes = createEnum([
|
||||
'GUILD_PUBLIC_THREAD',
|
||||
'GUILD_PRIVATE_THREAD',
|
||||
'GUILD_STAGE_VOICE',
|
||||
'GUILD_DIRECTORY',
|
||||
]);
|
||||
|
||||
/**
|
||||
@ -676,6 +680,13 @@ exports.ChannelTypes = createEnum([
|
||||
* @typedef {DMChannel|TextChannel|NewsChannel|ThreadChannel} TextBasedChannels
|
||||
*/
|
||||
|
||||
/**
|
||||
* Data that resolves to give a text-based channel. This can be:
|
||||
* * A text-based channel
|
||||
* * A snowflake
|
||||
* @typedef {TextBasedChannels|Snowflake} TextBasedChannelsResolvable
|
||||
*/
|
||||
|
||||
/**
|
||||
* The types of channels that are text-based. The available types are:
|
||||
* * DM
|
||||
@ -1160,6 +1171,7 @@ exports.ApplicationCommandOptionTypes = createEnum([
|
||||
'ROLE',
|
||||
'MENTIONABLE',
|
||||
'NUMBER',
|
||||
'ATTACHMENT',
|
||||
]);
|
||||
|
||||
/**
|
||||
@ -1186,6 +1198,7 @@ exports.InteractionTypes = createEnum([
|
||||
'APPLICATION_COMMAND',
|
||||
'MESSAGE_COMPONENT',
|
||||
'APPLICATION_COMMAND_AUTOCOMPLETE',
|
||||
'MODAL_SUBMIT',
|
||||
]);
|
||||
|
||||
/**
|
||||
@ -1209,6 +1222,7 @@ exports.InteractionResponseTypes = createEnum([
|
||||
'DEFERRED_MESSAGE_UPDATE',
|
||||
'UPDATE_MESSAGE',
|
||||
'APPLICATION_COMMAND_AUTOCOMPLETE_RESULT',
|
||||
'MODAL',
|
||||
]);
|
||||
|
||||
/**
|
||||
@ -1216,10 +1230,11 @@ exports.InteractionResponseTypes = createEnum([
|
||||
* * ACTION_ROW
|
||||
* * BUTTON
|
||||
* * SELECT_MENU
|
||||
* * TEXT_INPUT
|
||||
* @typedef {string} MessageComponentType
|
||||
* @see {@link https://discord.com/developers/docs/interactions/message-components#component-object-component-types}
|
||||
*/
|
||||
exports.MessageComponentTypes = createEnum([null, 'ACTION_ROW', 'BUTTON', 'SELECT_MENU']);
|
||||
exports.MessageComponentTypes = createEnum([null, 'ACTION_ROW', 'BUTTON', 'SELECT_MENU', 'TEXT_INPUT']);
|
||||
|
||||
/**
|
||||
* The style of a message button
|
||||
@ -1262,6 +1277,15 @@ exports.NSFWLevels = createEnum(['DEFAULT', 'EXPLICIT', 'SAFE', 'AGE_RESTRICTED'
|
||||
*/
|
||||
exports.PrivacyLevels = createEnum([null, 'PUBLIC', 'GUILD_ONLY']);
|
||||
|
||||
/**
|
||||
* The style of a text input component
|
||||
* * SHORT
|
||||
* * PARAGRAPH
|
||||
* @typedef {string} TextInputStyle
|
||||
* @see {@link https://discord.com/developers/docs/interactions/message-components#text-inputs-text-input-styles}
|
||||
*/
|
||||
exports.TextInputStyles = createEnum([null, 'SHORT', 'PARAGRAPH']);
|
||||
|
||||
/**
|
||||
* Privacy level of a {@link GuildScheduledEvent} object:
|
||||
* * GUILD_ONLY
|
||||
@ -1323,6 +1347,15 @@ exports.GuildScheduledEventStatuses = createEnum([null, 'SCHEDULED', 'ACTIVE', '
|
||||
*/
|
||||
exports.GuildScheduledEventEntityTypes = createEnum([null, 'STAGE_INSTANCE', 'VOICE', 'EXTERNAL']);
|
||||
/* eslint-enable max-len */
|
||||
/**
|
||||
* The camera video quality mode of a {@link VoiceChannel}:
|
||||
* * AUTO
|
||||
* * FULL
|
||||
* @typedef {string} VideoQualityMode
|
||||
* @see {@link https://discord.com/developers/docs/resources/channel#channel-object-video-quality-modes}
|
||||
*/
|
||||
exports.VideoQualityModes = createEnum([null, 'AUTO', 'FULL']);
|
||||
|
||||
exports.HypeSquadOptions = createEnum(['LEAVE', 'HOUSE_BRAVERY', 'HOUSE_BRILLIANCE', 'HOUSE_BALANCE']);
|
||||
|
||||
exports._cleanupSymbol = Symbol('djsCleanup');
|
||||
@ -1376,6 +1409,7 @@ function createEnum(keys) {
|
||||
* @property {StickerFormatType} StickerFormatTypes The value set for a sticker's format type.
|
||||
* @property {StickerType} StickerTypes The value set for a sticker's type.
|
||||
* @property {VerificationLevel} VerificationLevels The value set for the verification levels for a guild.
|
||||
* @property {VideoQualityMode} VideoQualityModes The camera video quality mode for a {@link VoiceChannel}.
|
||||
* @property {WebhookType} WebhookTypes The value set for a webhook's type.
|
||||
* @property {WSEventType} WSEvents The type of a WebSocket message event.
|
||||
*/
|
||||
|
@ -10,7 +10,6 @@ const {
|
||||
hyperlink,
|
||||
inlineCode,
|
||||
italic,
|
||||
memberNicknameMention,
|
||||
quote,
|
||||
roleMention,
|
||||
spoiler,
|
||||
@ -111,15 +110,6 @@ Formatters.inlineCode = inlineCode;
|
||||
*/
|
||||
Formatters.italic = italic;
|
||||
|
||||
/**
|
||||
* Formats a user id into a member-nickname mention.
|
||||
* @method memberNicknameMention
|
||||
* @memberof Formatters
|
||||
* @param {string} memberId The user id to format.
|
||||
* @returns {string}
|
||||
*/
|
||||
Formatters.memberNicknameMention = memberNicknameMention;
|
||||
|
||||
/**
|
||||
* Formats the content into a quote. This needs to be at the start of the line for Discord to format it.
|
||||
* @method quote
|
||||
|
@ -6,7 +6,7 @@ const JSONBig = require('json-bigint');
|
||||
/**
|
||||
* Rate limit data
|
||||
* @typedef {Object} RateLimitData
|
||||
* @property {number} timeout Time until this rate limit ends, in ms
|
||||
* @property {number} timeout Time until this rate limit ends, in milliseconds
|
||||
* @property {number} limit The maximum amount of requests of this endpoint
|
||||
* @property {string} method The HTTP method of this request
|
||||
* @property {string} path The path of the request relative to the HTTP endpoint
|
||||
@ -77,7 +77,7 @@ const JSONBig = require('json-bigint');
|
||||
* @property {PresenceData} [presence={}] Presence data to use upon login
|
||||
* @property {IntentsResolvable} [intents] Intents to enable for this connection
|
||||
* @property {number} [waitGuildTimeout=15_000] Time in milliseconds that Clients with the GUILDS intent should wait for
|
||||
* missing guilds to be recieved before starting the bot. If not specified, the default is 15 seconds.
|
||||
* missing guilds to be received before starting the bot. If not specified, the default is 15 seconds.
|
||||
* @property {SweeperOptions} [sweepers={}] Options for cache sweeping
|
||||
* @property {WebsocketOptions} [ws] Options for the WebSocket
|
||||
* @property {HTTPOptions} [http] HTTP options
|
||||
|
@ -16,7 +16,7 @@ class SnowflakeUtil extends null {
|
||||
* ```
|
||||
* 64 22 17 12 0
|
||||
* 000000111011000111100001101001000101000000 00001 00000 000000000000
|
||||
* number of ms since Discord epoch worker pid increment
|
||||
* number of milliseconds since Discord epoch worker pid increment
|
||||
* ```
|
||||
* @typedef {string} Snowflake
|
||||
*/
|
||||
|
@ -192,6 +192,15 @@ class Sweepers {
|
||||
return this._sweepGuildDirectProp('stageInstances', filter, { outputName: 'stage instances' }).items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sweeps all guild stickers and removes the ones which are indicated by the filter.
|
||||
* @param {Function} filter The function used to determine which stickers will be removed from the caches.
|
||||
* @returns {number} Amount of stickers that were removed from the caches
|
||||
*/
|
||||
sweepStickers(filter) {
|
||||
return this._sweepGuildDirectProp('stickers', filter).items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sweeps all thread members and removes the ones which are indicated by the filter.
|
||||
* <info>It is highly recommended to keep the client thread member cached</info>
|
||||
|
@ -10,6 +10,7 @@ const { Error: DiscordError, RangeError, TypeError } = require('../errors');
|
||||
const has = (o, k) => Object.prototype.hasOwnProperty.call(o, k);
|
||||
const isObject = d => typeof d === 'object' && d !== null;
|
||||
|
||||
let deprecationEmittedForSplitMessage = false;
|
||||
let deprecationEmittedForRemoveMentions = false;
|
||||
|
||||
/**
|
||||
@ -70,9 +71,19 @@ class Util extends null {
|
||||
* Splits a string into multiple chunks at a designated character that do not exceed a specific length.
|
||||
* @param {string} text Content to split
|
||||
* @param {SplitOptions} [options] Options controlling the behavior of the split
|
||||
* @deprecated This will be removed in the next major version.
|
||||
* @returns {string[]}
|
||||
*/
|
||||
static splitMessage(text, { maxLength = 2_000, char = '\n', prepend = '', append = '' } = {}) {
|
||||
if (!deprecationEmittedForSplitMessage) {
|
||||
process.emitWarning(
|
||||
'The Util.splitMessage method is deprecated and will be removed in the next major version.',
|
||||
'DeprecationWarning',
|
||||
);
|
||||
|
||||
deprecationEmittedForSplitMessage = true;
|
||||
}
|
||||
|
||||
text = Util.verifyString(text);
|
||||
if (text.length <= maxLength) return [text];
|
||||
let splitText = [text];
|
||||
@ -603,6 +614,17 @@ class Util extends null {
|
||||
filter.isDefault = true;
|
||||
return filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the maximum time a guild's thread channels should automatcally archive in case of no recent activity.
|
||||
* @param {Guild} guild The guild to resolve this limit from.
|
||||
* @returns {number}
|
||||
*/
|
||||
static resolveAutoArchiveMaxLimit({ features }) {
|
||||
if (features.includes('SEVEN_DAY_THREAD_ARCHIVE')) return 10080;
|
||||
if (features.includes('THREE_DAY_THREAD_ARCHIVE')) return 4320;
|
||||
return 1440;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Util;
|
||||
|
20
typings/enums.d.ts
vendored
20
typings/enums.d.ts
vendored
@ -79,6 +79,7 @@ export const enum ApplicationCommandOptionTypes {
|
||||
ROLE = 8,
|
||||
MENTIONABLE = 9,
|
||||
NUMBER = 10,
|
||||
ATTACHMENT = 11,
|
||||
}
|
||||
|
||||
export const enum ApplicationCommandPermissionTypes {
|
||||
@ -99,6 +100,7 @@ export const enum ChannelTypes {
|
||||
GUILD_PUBLIC_THREAD = 11,
|
||||
GUILD_PRIVATE_THREAD = 12,
|
||||
GUILD_STAGE_VOICE = 13,
|
||||
GUILD_DIRECTORY = 14,
|
||||
}
|
||||
|
||||
export const enum MessageTypes {
|
||||
@ -168,6 +170,7 @@ export const enum InteractionResponseTypes {
|
||||
DEFERRED_MESSAGE_UPDATE = 6,
|
||||
UPDATE_MESSAGE = 7,
|
||||
APPLICATION_COMMAND_AUTOCOMPLETE_RESULT = 8,
|
||||
MODAL = 9,
|
||||
}
|
||||
|
||||
export const enum InteractionTypes {
|
||||
@ -175,6 +178,7 @@ export const enum InteractionTypes {
|
||||
APPLICATION_COMMAND = 2,
|
||||
MESSAGE_COMPONENT = 3,
|
||||
APPLICATION_COMMAND_AUTOCOMPLETE = 4,
|
||||
MODAL_SUBMIT = 5,
|
||||
}
|
||||
|
||||
export const enum InviteTargetType {
|
||||
@ -199,6 +203,12 @@ export const enum MessageComponentTypes {
|
||||
ACTION_ROW = 1,
|
||||
BUTTON = 2,
|
||||
SELECT_MENU = 3,
|
||||
TEXT_INPUT = 4,
|
||||
}
|
||||
|
||||
export const enum ModalComponentTypes {
|
||||
ACTION_ROW = 1,
|
||||
TEXT_INPUT = 4,
|
||||
}
|
||||
|
||||
export const enum MFALevels {
|
||||
@ -241,6 +251,11 @@ export const enum StickerTypes {
|
||||
GUILD = 2,
|
||||
}
|
||||
|
||||
export const enum TextInputStyles {
|
||||
SHORT = 1,
|
||||
PARAGRAPH = 2,
|
||||
}
|
||||
|
||||
export const enum VerificationLevels {
|
||||
NONE = 0,
|
||||
LOW = 1,
|
||||
@ -249,6 +264,11 @@ export const enum VerificationLevels {
|
||||
VERY_HIGH = 4,
|
||||
}
|
||||
|
||||
export const enum VideoQualityModes {
|
||||
AUTO = 1,
|
||||
FULL = 2,
|
||||
}
|
||||
|
||||
export const enum WebhookTypes {
|
||||
Incoming = 1,
|
||||
'Channel Follower' = 2,
|
||||
|
1833
typings/index.d.ts
vendored
1833
typings/index.d.ts
vendored
File diff suppressed because it is too large
Load Diff
1306
typings/index.test-d.ts
Normal file
1306
typings/index.test-d.ts
Normal file
File diff suppressed because it is too large
Load Diff
10
typings/rawDataTypes.d.ts
vendored
10
typings/rawDataTypes.d.ts
vendored
@ -76,8 +76,13 @@ import {
|
||||
RESTPostAPIWebhookWithTokenJSONBody,
|
||||
Snowflake,
|
||||
APIGuildScheduledEvent,
|
||||
APIActionRowComponent,
|
||||
APITextInputComponent,
|
||||
APIModalActionRowComponent,
|
||||
APIModalSubmitInteraction,
|
||||
} from 'discord-api-types/v9';
|
||||
import { GuildChannel, Guild, PermissionOverwrites } from '.';
|
||||
import { GuildChannel, Guild, PermissionOverwrites, InteractionType } from '.';
|
||||
import type { InteractionTypes, MessageComponentTypes } from './enums';
|
||||
|
||||
export type RawActivityData = GatewayActivity;
|
||||
|
||||
@ -141,6 +146,9 @@ export type RawMessageComponentInteractionData = APIMessageComponentInteraction;
|
||||
export type RawMessageButtonInteractionData = APIMessageButtonInteractionData;
|
||||
export type RawMessageSelectMenuInteractionData = APIMessageSelectMenuInteractionData;
|
||||
|
||||
export type RawTextInputComponentData = APITextInputComponent;
|
||||
export type RawModalSubmitInteractionData = APIModalSubmitInteraction;
|
||||
|
||||
export type RawInviteData =
|
||||
| APIExtendedInvite
|
||||
| APIInvite
|
||||
|
Loading…
Reference in New Issue
Block a user