mirror of
https://github.com/discordjs/discord.js.git
synced 2026-05-23 12:00:09 +00:00
Compare commits
115 Commits
@discordjs
...
@discordjs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dceac0089d | ||
|
|
a2f7d3ad54 | ||
|
|
b532df61ed | ||
|
|
d60e0bf30b | ||
|
|
baa08b8fbb | ||
|
|
f469f74aca | ||
|
|
90d3b28268 | ||
|
|
a271e9b51e | ||
|
|
8ac0e1e5d6 | ||
|
|
9d6fdf8979 | ||
|
|
cafe58b3bd | ||
|
|
7eca844f6d | ||
|
|
63f5261f4c | ||
|
|
5be774db64 | ||
|
|
b36b751bde | ||
|
|
500712d5ea | ||
|
|
040c66ae15 | ||
|
|
82378fc2e8 | ||
|
|
d4f742e99e | ||
|
|
51ceb203fa | ||
|
|
1404e32849 | ||
|
|
9fc3e5ea72 | ||
|
|
19e74b1533 | ||
|
|
de22a10038 | ||
|
|
8ab30cdefa | ||
|
|
c2a43b685e | ||
|
|
507b696792 | ||
|
|
15f7571243 | ||
|
|
3fa429c7df | ||
|
|
7713627fd1 | ||
|
|
6a5c0fb32d | ||
|
|
eb5acd1e30 | ||
|
|
127021d5ab | ||
|
|
0943bc2efb | ||
|
|
a1c83c17d6 | ||
|
|
c0eae344c2 | ||
|
|
f2f757ce52 | ||
|
|
65cfa3ffd3 | ||
|
|
ee2eb7349f | ||
|
|
2d19163d76 | ||
|
|
9bca4af5fd | ||
|
|
fe5e344adc | ||
|
|
c8f6066d6a | ||
|
|
7e21a9474e | ||
|
|
d0a535ea6a | ||
|
|
8124fc68be | ||
|
|
dbd5354056 | ||
|
|
2ebb5cbd53 | ||
|
|
096cd92b87 | ||
|
|
37ef57b880 | ||
|
|
e3c247e423 | ||
|
|
5f3fc170fb | ||
|
|
20fade2a87 | ||
|
|
e827644b5a | ||
|
|
62815928ab | ||
|
|
7fb6630c02 | ||
|
|
737b80b5f2 | ||
|
|
481ccd228b | ||
|
|
a3fff7b8be | ||
|
|
8cdbe23766 | ||
|
|
d920933dc5 | ||
|
|
2d817df3b5 | ||
|
|
1605a2c289 | ||
|
|
464ea2ab30 | ||
|
|
0d1d54a537 | ||
|
|
dd8bb397a8 | ||
|
|
61d3d6d4ae | ||
|
|
512b0c67b9 | ||
|
|
532c3842bc | ||
|
|
edace17a13 | ||
|
|
d3154cf8f1 | ||
|
|
45552faf02 | ||
|
|
ebfd52695e | ||
|
|
595bded8a5 | ||
|
|
c74c632cdb | ||
|
|
fc003050de | ||
|
|
8702978057 | ||
|
|
c2b18d6d8b | ||
|
|
519aa3abe8 | ||
|
|
89c076c89e | ||
|
|
f224a07381 | ||
|
|
8e1e1be0c2 | ||
|
|
193a5e9e20 | ||
|
|
73c6bc2c36 | ||
|
|
b7f1ebc334 | ||
|
|
92aea94411 | ||
|
|
41dee5177d | ||
|
|
bbde371324 | ||
|
|
66b971899a | ||
|
|
43235d43fe | ||
|
|
31df3d21cd | ||
|
|
2663d76709 | ||
|
|
44a1e85847 | ||
|
|
d2e1924fa6 | ||
|
|
68dd260dee | ||
|
|
5e66f85f55 | ||
|
|
46060419a9 | ||
|
|
7c1b73cc69 | ||
|
|
95db597fc8 | ||
|
|
0047a49b73 | ||
|
|
32dff01f29 | ||
|
|
efa50fc3fa | ||
|
|
aa61c20ffd | ||
|
|
d48136bee1 | ||
|
|
46bf8f0146 | ||
|
|
7280d4e82e | ||
|
|
bd2914cc98 | ||
|
|
77804cfd55 | ||
|
|
8fea3ed978 | ||
|
|
05c63cd9a1 | ||
|
|
8d69b24b5c | ||
|
|
9baee4b2ce | ||
|
|
c986a99104 | ||
|
|
2b9e4cf9d0 | ||
|
|
1af2f4ed0e |
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -1,5 +1,5 @@
|
||||
# Learn how to add code owners here:
|
||||
# https://help.github.com/en/articles/about-code-owners
|
||||
# https://help.github.com/articles/about-code-owners
|
||||
|
||||
* @iCrawl
|
||||
|
||||
|
||||
2
.github/workflows/cleanup-cache.yml
vendored
2
.github/workflows/cleanup-cache.yml
vendored
@@ -1,4 +1,4 @@
|
||||
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#force-deleting-cache-entries
|
||||
# https://docs.github.com/actions/using-workflows/caching-dependencies-to-speed-up-workflows#force-deleting-cache-entries
|
||||
name: Cleanup caches
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
48
.github/workflows/documentation.yml
vendored
48
.github/workflows/documentation.yml
vendored
@@ -103,7 +103,15 @@ jobs:
|
||||
if: ${{ env.REF_TYPE == 'tag' && (!inputs.ref || inputs.ref == 'main') }}
|
||||
env:
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
CF_D1_DOCS_API_KEY: ${{ secrets.CF_D1_DOCS_API_KEY }}
|
||||
CF_D1_DOCS_ID: ${{ secrets.CF_D1_DOCS_ID }}
|
||||
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
|
||||
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
|
||||
CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}
|
||||
CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}
|
||||
CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}
|
||||
CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}
|
||||
CF_R2_DOCS_BUCKET_URL: ${{ secrets.CF_R2_DOCS_BUCKET_URL }}
|
||||
uses: ./packages/actions/src/uploadDocumentation
|
||||
with:
|
||||
package: ${{ steps.extract-tag.outputs.package }}
|
||||
@@ -113,7 +121,15 @@ jobs:
|
||||
if: ${{ env.REF_TYPE == 'tag' && inputs.ref && inputs.ref != 'main' }}
|
||||
env:
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
CF_D1_DOCS_API_KEY: ${{ secrets.CF_D1_DOCS_API_KEY }}
|
||||
CF_D1_DOCS_ID: ${{ secrets.CF_D1_DOCS_ID }}
|
||||
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
|
||||
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
|
||||
CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}
|
||||
CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}
|
||||
CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}
|
||||
CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}
|
||||
CF_R2_DOCS_BUCKET_URL: ${{ secrets.CF_R2_DOCS_BUCKET_URL }}
|
||||
uses: ./main/packages/actions/src/uploadDocumentation
|
||||
with:
|
||||
package: ${{ steps.extract-tag.outputs.package }}
|
||||
@@ -123,6 +139,10 @@ jobs:
|
||||
if: ${{ env.REF_TYPE == 'tag' && (!inputs.ref || inputs.ref == 'main') }}
|
||||
env:
|
||||
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
|
||||
CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}
|
||||
CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}
|
||||
CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}
|
||||
CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}
|
||||
uses: ./packages/actions/src/uploadSplitDocumentation
|
||||
with:
|
||||
package: ${{ steps.extract-tag.outputs.package }}
|
||||
@@ -132,6 +152,10 @@ jobs:
|
||||
if: ${{ env.REF_TYPE == 'tag' && inputs.ref && inputs.ref != 'main' }}
|
||||
env:
|
||||
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
|
||||
CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}
|
||||
CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}
|
||||
CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}
|
||||
CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}
|
||||
uses: ./main/packages/actions/src/uploadSplitDocumentation
|
||||
with:
|
||||
package: ${{ steps.extract-tag.outputs.package }}
|
||||
@@ -155,26 +179,50 @@ jobs:
|
||||
if: ${{ env.REF_TYPE == 'branch' && (!inputs.ref || inputs.ref == 'main') }}
|
||||
env:
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
CF_D1_DOCS_API_KEY: ${{ secrets.CF_D1_DOCS_API_KEY }}
|
||||
CF_D1_DOCS_ID: ${{ secrets.CF_D1_DOCS_ID }}
|
||||
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
|
||||
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
|
||||
CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}
|
||||
CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}
|
||||
CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}
|
||||
CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}
|
||||
CF_R2_DOCS_BUCKET_URL: ${{ secrets.CF_R2_DOCS_BUCKET_URL }}
|
||||
uses: ./packages/actions/src/uploadDocumentation
|
||||
|
||||
- name: Upload documentation to database
|
||||
if: ${{ env.REF_TYPE == 'branch' && inputs.ref && inputs.ref != 'main' }}
|
||||
env:
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
CF_D1_DOCS_API_KEY: ${{ secrets.CF_D1_DOCS_API_KEY }}
|
||||
CF_D1_DOCS_ID: ${{ secrets.CF_D1_DOCS_ID }}
|
||||
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
|
||||
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
|
||||
CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}
|
||||
CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}
|
||||
CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}
|
||||
CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}
|
||||
CF_R2_DOCS_BUCKET_URL: ${{ secrets.CF_R2_DOCS_BUCKET_URL }}
|
||||
uses: ./main/packages/actions/src/uploadDocumentation
|
||||
|
||||
- name: Upload split documentation to blob storage
|
||||
if: ${{ env.REF_TYPE == 'branch' && (!inputs.ref || inputs.ref == 'main') }}
|
||||
env:
|
||||
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
|
||||
CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}
|
||||
CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}
|
||||
CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}
|
||||
CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}
|
||||
uses: ./packages/actions/src/uploadSplitDocumentation
|
||||
|
||||
- name: Upload split documentation to blob storage
|
||||
if: ${{ env.REF_TYPE == 'branch' && inputs.ref && inputs.ref != 'main' }}
|
||||
env:
|
||||
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
|
||||
CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}
|
||||
CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}
|
||||
CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}
|
||||
CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}
|
||||
uses: ./main/packages/actions/src/uploadSplitDocumentation
|
||||
|
||||
- name: Move docs to correct directory
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
<a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/v/discord.js.svg?maxAge=3600" alt="npm version" /></a>
|
||||
<a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/dt/discord.js.svg?maxAge=3600" alt="npm downloads" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Tests status" /></a>
|
||||
<a href="https://codecov.io/gh/discordjs/discord.js" ><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2" alt="Code coverage" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/commits/main"><img src="https://img.shields.io/github/last-commit/discordjs/discord.js.svg?logo=github&logoColor=ffffff" alt="Last commit." /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/graphs/contributors"><img src="https://img.shields.io/github/contributors/discordjs/discord.js.svg?maxAge=3600&logo=github&logoColor=fff&color=00c7be" alt="contributors" /></a>
|
||||
<a href="https://codecov.io/gh/discordjs/discord.js"><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2" alt="Code coverage" /></a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://vercel.com/?utm_source=discordjs&utm_campaign=oss"><img src="https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg" alt="Vercel" /></a>
|
||||
|
||||
@@ -18,8 +18,9 @@ export async function Badges({ node }: { readonly node: any }) {
|
||||
const isAbstract = node.isAbstract;
|
||||
const isReadonly = node.isReadonly;
|
||||
const isOptional = node.isOptional;
|
||||
const isExternal = node.isExternal;
|
||||
|
||||
const isAny = isDeprecated || isProtected || isStatic || isAbstract || isReadonly || isOptional;
|
||||
const isAny = isDeprecated || isProtected || isStatic || isAbstract || isReadonly || isOptional || isExternal;
|
||||
|
||||
return isAny ? (
|
||||
<div className="mb-1 flex gap-3">
|
||||
@@ -33,6 +34,7 @@ export async function Badges({ node }: { readonly node: any }) {
|
||||
{isAbstract ? <Badge className="bg-cyan-500/20 text-cyan-500">abstract</Badge> : null}
|
||||
{isReadonly ? <Badge className="bg-purple-500/20 text-purple-500">readonly</Badge> : null}
|
||||
{isOptional ? <Badge className="bg-cyan-500/20 text-cyan-500">optional</Badge> : null}
|
||||
{isExternal ? <Badge className="bg-purple-500/20 text-purple-500">external</Badge> : null}
|
||||
</div>
|
||||
) : null;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ export async function ParameterNode({
|
||||
{description ? <Badges node={parameter} /> : null}
|
||||
{parameter.name}
|
||||
{parameter.isOptional ? '?' : ''}: <ExcerptNode node={parameter.typeExcerpt} version={version} />
|
||||
{parameter.defaultValue ? ` = ${parameter.defaultValue}` : ''}
|
||||
</span>
|
||||
{description && parameter.description?.length ? (
|
||||
<div className="mt-4 pl-4">
|
||||
|
||||
@@ -51,7 +51,13 @@ export async function PropertyNode({
|
||||
<LinkIcon aria-hidden size={16} />
|
||||
</Link>
|
||||
{property.displayName}
|
||||
{property.isOptional ? '?' : ''} : <ExcerptNode node={property.typeExcerpt} version={version} />
|
||||
{property.isOptional ? '?' : ''} : <ExcerptNode node={property.typeExcerpt} version={version} />{' '}
|
||||
{property.summary?.defaultValueBlock.length
|
||||
? `= ${property.summary.defaultValueBlock.reduce(
|
||||
(acc: string, def: { kind: string; text: string }) => `${acc}${def.text}`,
|
||||
'',
|
||||
)}`
|
||||
: ''}
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
|
||||
14
package.json
14
package.json
@@ -6,19 +6,19 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "turbo run build --concurrency=4",
|
||||
"build:affected": "turbo run build --filter=...[origin/main] --concurrency=4",
|
||||
"build:affected": "turbo run build --filter=...[origin/v14] --concurrency=4",
|
||||
"build:apps": "turbo run build:local --filter=...{apps/*} --concurrency=4",
|
||||
"build:apps:affected": "turbo run build:local --filter=...{apps/*}[origin/main] --concurrency=4",
|
||||
"build:apps:affected": "turbo run build:local --filter=...{apps/*}[origin/v14] --concurrency=4",
|
||||
"test": "turbo run test --concurrency=4",
|
||||
"test:affected": "turbo run test --filter=...[origin/main] --concurrency=4",
|
||||
"test:affected": "turbo run test --filter=...[origin/v14] --concurrency=4",
|
||||
"lint": "turbo run lint --concurrency=4",
|
||||
"lint:affected": "turbo run lint --filter=...[origin/main] --concurrency=4",
|
||||
"lint:affected": "turbo run lint --filter=...[origin/v14] --concurrency=4",
|
||||
"format": "turbo run format --concurrency=4",
|
||||
"format:affected": "turbo run format --filter=...[origin/main] --concurrency=4",
|
||||
"format:affected": "turbo run format --filter=...[origin/v14] --concurrency=4",
|
||||
"fmt": "turbo run format --concurrency=4",
|
||||
"fmt:affected": "turbo run format --filter=...[origin/main] --concurrency=4",
|
||||
"fmt:affected": "turbo run format --filter=...[origin/v14] --concurrency=4",
|
||||
"docs": "turbo run docs --concurrency=4",
|
||||
"docs:affected": "turbo run docs --filter=...[origin/main] --concurrency=4",
|
||||
"docs:affected": "turbo run docs --filter=...[origin/v14] --concurrency=4",
|
||||
"prepare": "is-ci || husky",
|
||||
"update": "pnpm --recursive update --interactive",
|
||||
"update:latest": "pnpm --recursive update --interactive --latest",
|
||||
|
||||
@@ -41,28 +41,32 @@
|
||||
"homepage": "https://discord.js.org",
|
||||
"funding": "https://github.com/discordjs/discord.js?sponsor",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.1",
|
||||
"@actions/core": "^1.11.1",
|
||||
"@actions/glob": "^0.5.0",
|
||||
"@aws-sdk/client-s3": "^3.787.0",
|
||||
"@discordjs/scripts": "workspace:^",
|
||||
"@vercel/blob": "^0.23.4",
|
||||
"@vercel/blob": "^0.27.3",
|
||||
"@vercel/postgres": "^0.9.0",
|
||||
"cloudflare": "^4.2.0",
|
||||
"meilisearch": "^0.38.0",
|
||||
"p-limit": "^6.1.0",
|
||||
"tslib": "^2.6.3",
|
||||
"undici": "6.19.8"
|
||||
"p-limit": "^6.2.0",
|
||||
"p-queue": "^8.1.0",
|
||||
"tslib": "^2.8.1",
|
||||
"undici": "7.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.19.45",
|
||||
"@vitest/coverage-v8": "^2.0.5",
|
||||
"@types/node": "^22.14.0",
|
||||
"@vitest/coverage-v8": "^3.1.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"prettier": "^3.3.3",
|
||||
"tsup": "^8.2.4",
|
||||
"turbo": "^2.0.14",
|
||||
"typescript": "~5.5.4",
|
||||
"vitest": "^2.0.5"
|
||||
"prettier": "^3.5.3",
|
||||
"terser": "^5.37.0",
|
||||
"tsup": "^8.4.0",
|
||||
"turbo": "^2.5.0",
|
||||
"typescript": "~5.8.3",
|
||||
"vitest": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
||||
@@ -9,7 +9,7 @@ runs:
|
||||
with:
|
||||
swap-size-gb: 10
|
||||
|
||||
- uses: pnpm/action-setup@v4.0.0
|
||||
- uses: pnpm/action-setup@v4.1.0
|
||||
name: Install pnpm
|
||||
with:
|
||||
run_install: false
|
||||
|
||||
@@ -1,13 +1,26 @@
|
||||
/* eslint-disable @typescript-eslint/no-loop-func */
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import process from 'node:process';
|
||||
import { getInput, setFailed } from '@actions/core';
|
||||
import { create } from '@actions/glob';
|
||||
import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
|
||||
import { put } from '@vercel/blob';
|
||||
import { createPool } from '@vercel/postgres';
|
||||
import Cloudflare from 'cloudflare';
|
||||
import pLimit from 'p-limit';
|
||||
|
||||
if (!process.env.DATABASE_URL) {
|
||||
setFailed('DATABASE_URL is not set');
|
||||
if (
|
||||
!process.env.DATABASE_URL ||
|
||||
!process.env.CF_R2_DOCS_URL ||
|
||||
!process.env.CF_R2_DOCS_ACCESS_KEY_ID ||
|
||||
!process.env.CF_R2_DOCS_SECRET_ACCESS_KEY ||
|
||||
!process.env.CF_R2_DOCS_BUCKET ||
|
||||
!process.env.CF_R2_DOCS_BUCKET_URL ||
|
||||
!process.env.CF_D1_DOCS_API_KEY ||
|
||||
!process.env.CF_D1_DOCS_ID ||
|
||||
!process.env.CF_ACCOUNT_ID
|
||||
) {
|
||||
setFailed('Missing environment variables');
|
||||
}
|
||||
|
||||
const pkg = getInput('package') || '*';
|
||||
@@ -17,6 +30,21 @@ const pool = createPool({
|
||||
connectionString: process.env.DATABASE_URL,
|
||||
});
|
||||
|
||||
const S3 = new S3Client({
|
||||
region: 'auto',
|
||||
endpoint: process.env.CF_R2_DOCS_URL!,
|
||||
credentials: {
|
||||
accessKeyId: process.env.CF_R2_DOCS_ACCESS_KEY_ID!,
|
||||
secretAccessKey: process.env.CF_R2_DOCS_SECRET_ACCESS_KEY!,
|
||||
},
|
||||
requestChecksumCalculation: 'WHEN_REQUIRED',
|
||||
responseChecksumValidation: 'WHEN_REQUIRED',
|
||||
});
|
||||
|
||||
const client = new Cloudflare({
|
||||
apiToken: process.env.CF_D1_DOCS_API_KEY,
|
||||
});
|
||||
|
||||
const limit = pLimit(10);
|
||||
const promises = [];
|
||||
|
||||
@@ -26,12 +54,14 @@ for await (const file of globber.globGenerator()) {
|
||||
const data = await readFile(file, 'utf8');
|
||||
try {
|
||||
promises.push(
|
||||
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
||||
limit(async () => {
|
||||
console.log(`Uploading ${file} with ${version}...`);
|
||||
const json = JSON.parse(data);
|
||||
const name = json.name ?? json.n;
|
||||
const { url } = await put(`${name.replace('@discordjs/', '')}/${version}.json`, data, {
|
||||
|
||||
const key = `${name.replace('@discordjs/', '')}/${version}.json`;
|
||||
|
||||
const { url } = await put(key, data, {
|
||||
access: 'public',
|
||||
addRandomSuffix: false,
|
||||
});
|
||||
@@ -39,6 +69,19 @@ for await (const file of globber.globGenerator()) {
|
||||
'@discordjs/',
|
||||
'',
|
||||
)}, ${version}, ${url}) on conflict (name, version) do update set url = EXCLUDED.url`;
|
||||
|
||||
await S3.send(
|
||||
new PutObjectCommand({
|
||||
Bucket: process.env.CF_R2_DOCS_BUCKET,
|
||||
Key: key,
|
||||
Body: data,
|
||||
}),
|
||||
);
|
||||
await client.d1.database.raw(process.env.CF_D1_DOCS_ID!, {
|
||||
account_id: process.env.CF_ACCOUNT_ID!,
|
||||
sql: `insert into documentation (name, version, url) values (?, ?, ?) on conflict (name, version) do update set url = excluded.url;`,
|
||||
params: [name.replace('@discordjs/', ''), version, process.env.CF_R2_DOCS_BUCKET_URL + '/' + key],
|
||||
});
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,32 +1,82 @@
|
||||
/* eslint-disable @typescript-eslint/no-loop-func */
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { basename, dirname, relative, sep } from 'node:path';
|
||||
import { cwd } from 'node:process';
|
||||
import { getInput } from '@actions/core';
|
||||
import process from 'node:process';
|
||||
import { setTimeout as sleep } from 'node:timers/promises';
|
||||
import { setFailed, getInput } from '@actions/core';
|
||||
import { create } from '@actions/glob';
|
||||
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
|
||||
import { put } from '@vercel/blob';
|
||||
import pLimit from 'p-limit';
|
||||
import PQueue from 'p-queue';
|
||||
|
||||
if (
|
||||
!process.env.CF_R2_DOCS_URL ||
|
||||
!process.env.CF_R2_DOCS_ACCESS_KEY_ID ||
|
||||
!process.env.CF_R2_DOCS_SECRET_ACCESS_KEY ||
|
||||
!process.env.CF_R2_DOCS_BUCKET
|
||||
) {
|
||||
setFailed('Missing environment variables');
|
||||
}
|
||||
|
||||
const pkg = getInput('package') || '*';
|
||||
const version = getInput('version') || 'main';
|
||||
|
||||
const limit = pLimit(10);
|
||||
const queue = new PQueue({ concurrency: 10, interval: 60_000, intervalCap: 1_000 });
|
||||
const promises = [];
|
||||
const failedUploads: string[] = [];
|
||||
|
||||
const S3 = new S3Client({
|
||||
region: 'auto',
|
||||
endpoint: process.env.CF_R2_DOCS_URL!,
|
||||
credentials: {
|
||||
accessKeyId: process.env.CF_R2_DOCS_ACCESS_KEY_ID!,
|
||||
secretAccessKey: process.env.CF_R2_DOCS_SECRET_ACCESS_KEY!,
|
||||
},
|
||||
requestChecksumCalculation: 'WHEN_REQUIRED',
|
||||
responseChecksumValidation: 'WHEN_REQUIRED',
|
||||
});
|
||||
|
||||
const globber = await create(`packages/${pkg}/docs/${pkg}/split/*.api.json`);
|
||||
console.log('Glob: ', await globber.glob());
|
||||
for await (const file of globber.globGenerator()) {
|
||||
const data = await readFile(file, 'utf8');
|
||||
const pkgName = dirname(relative(cwd(), file)).split(sep)[1];
|
||||
const pkgName = dirname(relative(process.cwd(), file)).split(sep)[1];
|
||||
try {
|
||||
promises.push(
|
||||
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
||||
limit(async () => {
|
||||
queue.add(async () => {
|
||||
console.log(`Uploading ${file} with ${version} from ${pkgName}...`);
|
||||
const name = basename(file).replace('main.', '');
|
||||
await put(`rewrite/${pkgName}/${version}.${name}`, data, {
|
||||
access: 'public',
|
||||
addRandomSuffix: false,
|
||||
});
|
||||
async function upload(retries = 0) {
|
||||
try {
|
||||
await put(`rewrite/${pkgName}/${version}.${name}`, data, {
|
||||
access: 'public',
|
||||
addRandomSuffix: false,
|
||||
});
|
||||
await S3.send(
|
||||
new PutObjectCommand({
|
||||
Bucket: process.env.CF_R2_DOCS_BUCKET,
|
||||
Key: `${pkgName}/${version}.${name}`,
|
||||
Body: data,
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
if (retries > 3) {
|
||||
console.error(`Could not upload ${file} after 3 retries`, error);
|
||||
failedUploads.push(name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof error === 'object' && error && 'retryAfter' in error && typeof error.retryAfter === 'number') {
|
||||
await sleep(error.retryAfter * 1_000);
|
||||
return upload(retries + 1);
|
||||
} else {
|
||||
console.error(`Could not upload ${file}`, error);
|
||||
failedUploads.push(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await upload();
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
@@ -36,6 +86,9 @@ for await (const file of globber.globGenerator()) {
|
||||
|
||||
try {
|
||||
await Promise.all(promises);
|
||||
if (failedUploads.length) {
|
||||
setFailed(`Failed to upload ${failedUploads.length} files: ${failedUploads.join(', ')}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
10
packages/actions/tsconfig.test.json
Normal file
10
packages/actions/tsconfig.test.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig.json",
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"noEmit": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["__tests__/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import type { IExcerptTokenRange } from './Excerpt.js';
|
||||
* @public
|
||||
*/
|
||||
export interface IApiParameterOptions {
|
||||
defaultValue: string | undefined;
|
||||
isOptional: boolean;
|
||||
isRest: boolean;
|
||||
parameterName: string;
|
||||
@@ -124,6 +125,7 @@ export function ApiParameterListMixin<TBaseClass extends IApiItemConstructor>(
|
||||
isOptional: Boolean(parameterOptions.isOptional),
|
||||
isRest: Boolean(parameterOptions.isRest),
|
||||
parent: this,
|
||||
defaultValue: parameterOptions.defaultValue,
|
||||
});
|
||||
|
||||
this[_parameters].push(parameter);
|
||||
@@ -171,6 +173,7 @@ export function ApiParameterListMixin<TBaseClass extends IApiItemConstructor>(
|
||||
parameterTypeTokenRange: parameter.parameterTypeExcerpt.tokenRange,
|
||||
isOptional: parameter.isOptional,
|
||||
isRest: parameter.isRest,
|
||||
defaultValue: parameter.defaultValue,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ const MinifyJSONMapping = {
|
||||
constraintTokenRange: 'ctr',
|
||||
dependencies: 'dp',
|
||||
defaultTypeTokenRange: 'dtr',
|
||||
defaultValue: 'dv',
|
||||
docComment: 'd',
|
||||
endIndex: 'en',
|
||||
excerptTokens: 'ex',
|
||||
|
||||
@@ -262,6 +262,7 @@ function mapParam(
|
||||
startIndex: 1 + index + paramTokens.slice(0, index).reduce((akk, num) => akk + num, 0),
|
||||
endIndex: 1 + index + paramTokens.slice(0, index + 1).reduce((akk, num) => akk + num, 0),
|
||||
},
|
||||
defaultValue: param.default,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import type { Excerpt } from '../mixins/Excerpt.js';
|
||||
* @public
|
||||
*/
|
||||
export interface IParameterOptions {
|
||||
defaultValue: string | undefined;
|
||||
isOptional: boolean;
|
||||
isRest: boolean;
|
||||
name: string;
|
||||
@@ -56,6 +57,11 @@ export class Parameter {
|
||||
*/
|
||||
public isRest: boolean;
|
||||
|
||||
/**
|
||||
* The default value for this parameter if optional
|
||||
*/
|
||||
public defaultValue: string | undefined;
|
||||
|
||||
private readonly _parent: ApiParameterListMixin;
|
||||
|
||||
public constructor(options: IParameterOptions) {
|
||||
@@ -64,6 +70,7 @@ export class Parameter {
|
||||
this.isOptional = options.isOptional;
|
||||
this.isRest = options.isRest;
|
||||
this._parent = options.parent;
|
||||
this.defaultValue = options.defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -843,6 +843,7 @@ export class ApiModelGenerator {
|
||||
const parameters: IApiParameterOptions[] = this._captureParameters(
|
||||
nodesToCapture,
|
||||
functionDeclaration.parameters,
|
||||
jsDoc?.params,
|
||||
);
|
||||
|
||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||
@@ -1043,6 +1044,7 @@ export class ApiModelGenerator {
|
||||
const parameters: IApiParameterOptions[] = this._captureParameters(
|
||||
nodesToCapture,
|
||||
methodDeclaration.parameters,
|
||||
jsDoc?.params,
|
||||
);
|
||||
|
||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||
@@ -1137,7 +1139,11 @@ export class ApiModelGenerator {
|
||||
methodSignature.typeParameters,
|
||||
);
|
||||
|
||||
const parameters: IApiParameterOptions[] = this._captureParameters(nodesToCapture, methodSignature.parameters);
|
||||
const parameters: IApiParameterOptions[] = this._captureParameters(
|
||||
nodesToCapture,
|
||||
methodSignature.parameters,
|
||||
jsDoc?.params,
|
||||
);
|
||||
|
||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
||||
@@ -1342,7 +1348,7 @@ export class ApiModelGenerator {
|
||||
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
||||
const docComment: tsdoc.DocComment | undefined = jsDoc
|
||||
? this._tsDocParser.parseString(
|
||||
`/**\n * ${this._fixLinkTags(jsDoc.description) ?? ''}${jsDoc.default ? ` (default: ${this._escapeSpecialChars(jsDoc.default)})` : ''}\n${
|
||||
`/**\n * ${this._fixLinkTags(jsDoc.description) ?? ''}${jsDoc.default ? `\n * @defaultValue ${this._escapeSpecialChars(jsDoc.default)}` : ''}\n${
|
||||
'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\n`).join('') : ''
|
||||
}${'readonly' in jsDoc && jsDoc.readonly ? ' * @readonly\n' : ''}${
|
||||
'deprecated' in jsDoc && jsDoc.deprecated
|
||||
@@ -1529,6 +1535,7 @@ export class ApiModelGenerator {
|
||||
},
|
||||
isOptional: Boolean(parameter.optional),
|
||||
isRest: parameter.name.startsWith('...'),
|
||||
defaultValue: parameter.default?.toString(),
|
||||
});
|
||||
excerptTokens.push(...newTokens);
|
||||
excerptTokens.push({
|
||||
@@ -1548,6 +1555,7 @@ export class ApiModelGenerator {
|
||||
},
|
||||
isOptional: Boolean(parameter.optional),
|
||||
isRest: parameter.name.startsWith('...'),
|
||||
defaultValue: parameter.default?.toString(),
|
||||
});
|
||||
excerptTokens.push(...newTokens);
|
||||
excerptTokens.push({
|
||||
@@ -1640,6 +1648,7 @@ export class ApiModelGenerator {
|
||||
private _captureParameters(
|
||||
nodesToCapture: IExcerptBuilderNodeToCapture[],
|
||||
parameterNodes: ts.NodeArray<ts.ParameterDeclaration>,
|
||||
jsDoc?: DocgenParamJson[] | undefined,
|
||||
): IApiParameterOptions[] {
|
||||
const parameters: IApiParameterOptions[] = [];
|
||||
for (const parameter of parameterNodes) {
|
||||
@@ -1650,6 +1659,9 @@ export class ApiModelGenerator {
|
||||
parameterTypeTokenRange,
|
||||
isOptional: this._collector.typeChecker.isOptionalParameter(parameter),
|
||||
isRest: Boolean(parameter.dotDotDotToken),
|
||||
defaultValue:
|
||||
parameter.initializer?.getText() ??
|
||||
jsDoc?.find((param) => param.name === parameter.name.getText().trim())?.default?.toString(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1753,7 +1765,7 @@ export class ApiModelGenerator {
|
||||
return input;
|
||||
}
|
||||
|
||||
return input.replaceAll(/(?<char>[{}])/g, '\\$<char>');
|
||||
return input.replaceAll(/(?<char>[@{}])/g, '\\$<char>');
|
||||
}
|
||||
|
||||
private _fixLinkTags(input?: string): string | undefined {
|
||||
@@ -1848,7 +1860,7 @@ export class ApiModelGenerator {
|
||||
isOptional: Boolean(prop.nullable),
|
||||
isReadonly: Boolean(prop.readonly),
|
||||
docComment: this._tsDocParser.parseString(
|
||||
`/**\n * ${this._fixLinkTags(prop.description) ?? ''}${prop.default ? ` (default: ${this._escapeSpecialChars(prop.default)})` : ''}\n${
|
||||
`/**\n * ${this._fixLinkTags(prop.description) ?? ''}\n${prop.default ? ` * @defaultValue ${this._escapeSpecialChars(prop.default)}\n` : ''}${
|
||||
prop.see?.map((see) => ` * @see ${see}\n`).join('') ?? ''
|
||||
}${prop.readonly ? ' * @readonly\n' : ''} */`,
|
||||
).docComment,
|
||||
@@ -1860,7 +1872,7 @@ export class ApiModelGenerator {
|
||||
}${prop.name} :`,
|
||||
},
|
||||
...mappedVarType,
|
||||
{ kind: ExcerptTokenKind.Content, text: ';' },
|
||||
{ kind: ExcerptTokenKind.Content, text: `${prop.default ? ` = ${prop.default}` : ''};` },
|
||||
],
|
||||
propertyTypeTokenRange: { startIndex: 1, endIndex: 1 + mappedVarType.length },
|
||||
releaseTag: prop.access === 'private' ? ReleaseTag.Internal : ReleaseTag.Public,
|
||||
@@ -1883,6 +1895,7 @@ export class ApiModelGenerator {
|
||||
startIndex: 1 + index + paramTokens.slice(0, index).reduce((akk, num) => akk + num, 0),
|
||||
endIndex: 1 + index + paramTokens.slice(0, index + 1).reduce((akk, num) => akk + num, 0),
|
||||
},
|
||||
defaultValue: param.default?.toString(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1907,7 +1920,7 @@ export class ApiModelGenerator {
|
||||
excerptTokens.push(...newTokens);
|
||||
excerptTokens.push({
|
||||
kind: ExcerptTokenKind.Content,
|
||||
text: `, ${method.params![index + 1]!.name}${
|
||||
text: `${method.params![index]!.default ? ` = ${method.params![index]!.default}` : ''}, ${method.params![index + 1]!.name}${
|
||||
method.params![index + 1]!.nullable || method.params![index + 1]!.optional ? '?' : ''
|
||||
}: `,
|
||||
});
|
||||
@@ -1917,7 +1930,10 @@ export class ApiModelGenerator {
|
||||
const newTokens = this._mapVarType(method.params[method.params.length - 1]!.type);
|
||||
paramTokens.push(newTokens.length);
|
||||
excerptTokens.push(...newTokens);
|
||||
excerptTokens.push({ kind: ExcerptTokenKind.Content, text: `): ` });
|
||||
excerptTokens.push({
|
||||
kind: ExcerptTokenKind.Content,
|
||||
text: `${method.params![method.params.length - 1]!.default ? ` = ${method.params![method.params.length - 1]!.default}` : ''}): `,
|
||||
});
|
||||
}
|
||||
|
||||
const returnTokens = this._mapVarType(method.returns?.[0] ?? []);
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
<a href="https://www.npmjs.com/package/@discordjs/brokers"><img src="https://img.shields.io/npm/v/@discordjs/brokers.svg?maxAge=3600" alt="npm version" /></a>
|
||||
<a href="https://www.npmjs.com/package/@discordjs/brokers"><img src="https://img.shields.io/npm/dt/@discordjs/brokers.svg?maxAge=3600" alt="npm downloads" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Build status" /></a>
|
||||
<a href="https://codecov.io/gh/discordjs/discord.js" ><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=brokers" alt="Code coverage" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/commits/main/packages/brokers"><img alt="Last commit." src="https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fbrokers"></a>
|
||||
<a href="https://codecov.io/gh/discordjs/discord.js"><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=brokers" alt="Code coverage" /></a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://vercel.com/?utm_source=discordjs&utm_campaign=oss"><img src="https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg" alt="Vercel" /></a>
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
<a href="https://www.npmjs.com/package/@discordjs/builders"><img src="https://img.shields.io/npm/v/@discordjs/builders.svg?maxAge=3600" alt="npm version" /></a>
|
||||
<a href="https://www.npmjs.com/package/@discordjs/builders"><img src="https://img.shields.io/npm/dt/@discordjs/builders.svg?maxAge=3600" alt="npm downloads" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Build status" /></a>
|
||||
<a href="https://codecov.io/gh/discordjs/discord.js" ><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=builders" alt="Code coverage" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/commits/main/packages/builders"><img alt="Last commit." src="https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fbuilders"></a>
|
||||
<a href="https://codecov.io/gh/discordjs/discord.js"><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=builders" alt="Code coverage" /></a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://vercel.com/?utm_source=discordjs&utm_campaign=oss"><img src="https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg" alt="Vercel" /></a>
|
||||
|
||||
@@ -565,7 +565,7 @@ describe('Slash Commands', () => {
|
||||
});
|
||||
|
||||
describe('integration types', () => {
|
||||
test('GIVEN a builder with valid integraton types THEN does not throw an error', () => {
|
||||
test('GIVEN a builder with valid integration types THEN does not throw an error', () => {
|
||||
expect(() =>
|
||||
getBuilder().setIntegrationTypes([
|
||||
ApplicationIntegrationType.GuildInstall,
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
"@discordjs/formatters": "workspace:^",
|
||||
"@discordjs/util": "workspace:^",
|
||||
"@sapphire/shapeshift": "^4.0.0",
|
||||
"discord-api-types": "^0.37.114",
|
||||
"discord-api-types": "^0.37.119",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"ts-mixer": "^6.0.4",
|
||||
"tslib": "^2.6.3"
|
||||
|
||||
@@ -83,7 +83,7 @@ export class StringSelectMenuBuilder extends BaseSelectMenuBuilder<APIStringSele
|
||||
*
|
||||
* @remarks
|
||||
* This method behaves similarly
|
||||
* to {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice | Array.prototype.splice()}.
|
||||
* to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/slice | Array.prototype.splice()}.
|
||||
* It's useful for modifying and adjusting the order of existing options.
|
||||
* @example
|
||||
* Remove the first option:
|
||||
|
||||
@@ -125,7 +125,7 @@ export class EmbedBuilder {
|
||||
*
|
||||
* @remarks
|
||||
* This method behaves similarly
|
||||
* to {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.
|
||||
* to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.
|
||||
* The maximum amount of fields that can be added is 25.
|
||||
*
|
||||
* It's useful for modifying and adjusting order of the already-existing fields of an embed.
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
<a href="https://www.npmjs.com/package/@discordjs/collection"><img src="https://img.shields.io/npm/v/@discordjs/collection.svg?maxAge=3600" alt="npm version" /></a>
|
||||
<a href="https://www.npmjs.com/package/@discordjs/collection"><img src="https://img.shields.io/npm/dt/@discordjs/collection.svg?maxAge=3600" alt="npm downloads" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Build status" /></a>
|
||||
<a href="https://codecov.io/gh/discordjs/discord.js" ><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=collection" alt="Code coverage" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/commits/main/packages/collection"><img alt="Last commit." src="https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fcollection"></a>
|
||||
<a href="https://codecov.io/gh/discordjs/discord.js"><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=collection" alt="Code coverage" /></a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://vercel.com/?utm_source=discordjs&utm_campaign=oss"><img src="https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg" alt="Vercel" /></a>
|
||||
|
||||
@@ -2,6 +2,30 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
# [@discordjs/core@2.2.1](https://github.com/discordjs/discord.js/compare/@discordjs/core@2.2.0...@discordjs/core@2.2.1) - (2025-08-20)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- Adjust `reason` in methods options (#10977) ([9fc3e5e](https://github.com/discordjs/discord.js/commit/9fc3e5ea72a2714d81cc57cbac4f378a49934446))
|
||||
|
||||
# [@discordjs/core@2.2.0](https://github.com/discordjs/discord.js/compare/@discordjs/core@2.1.1...@discordjs/core@2.2.0) - (2025-06-25)
|
||||
|
||||
## Features
|
||||
|
||||
- **webhook:** Support `with_components` (#10945) ([7713627](https://github.com/discordjs/discord.js/commit/7713627fd18599a6187b325e1e4bc9a17cf23e21))
|
||||
|
||||
# [@discordjs/core@2.1.1](https://github.com/discordjs/discord.js/compare/@discordjs/core@2.1.0...@discordjs/core@2.1.1) - (2025-06-16)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **guild:** Fix incorrectly-detected deprecated overload ([d0a535e](https://github.com/discordjs/discord.js/commit/d0a535ea6a66861276691a51547adfb2bcef0384))
|
||||
|
||||
# [@discordjs/core@2.1.0](https://github.com/discordjs/discord.js/compare/@discordjs/core@2.0.1...@discordjs/core@2.1.0) - (2025-04-25)
|
||||
|
||||
## Features
|
||||
|
||||
- **website:** Include reexported members in docs (#10518) ([aa61c20](https://github.com/discordjs/discord.js/commit/aa61c20ffdac3f3a0dca224f9e48e614309ecb2e))
|
||||
|
||||
# [@discordjs/core@2.0.0](https://github.com/discordjs/discord.js/compare/@discordjs/core@1.2.0...@discordjs/core@2.0.0) - (2024-09-01)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
<a href="https://www.npmjs.com/package/@discordjs/core"><img src="https://img.shields.io/npm/v/@discordjs/core.svg?maxAge=3600" alt="npm version" /></a>
|
||||
<a href="https://www.npmjs.com/package/@discordjs/core"><img src="https://img.shields.io/npm/dt/@discordjs/core.svg?maxAge=3600" alt="npm downloads" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Build status" /></a>
|
||||
<a href="https://codecov.io/gh/discordjs/discord.js" ><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=core" alt="Code coverage" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/commits/main/packages/core"><img alt="Last commit." src="https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fcore"></a>
|
||||
<a href="https://codecov.io/gh/discordjs/discord.js"><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=core" alt="Code coverage" /></a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://vercel.com/?utm_source=discordjs&utm_campaign=oss"><img src="https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg" alt="Vercel" /></a>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"extends": "../../api-extractor.json",
|
||||
"bundledPackages": ["discord-api-types"],
|
||||
"docModel": {
|
||||
"projectFolderUrl": "https://github.com/discordjs/discord.js/tree/main/packages/core"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@discordjs/core",
|
||||
"version": "2.0.0",
|
||||
"version": "2.2.1",
|
||||
"description": "A thinly abstracted wrapper around the rest API, and gateway.",
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
@@ -70,7 +70,7 @@
|
||||
"@discordjs/ws": "workspace:^",
|
||||
"@sapphire/snowflake": "^3.5.3",
|
||||
"@vladfrangu/async_event_emitter": "^2.4.6",
|
||||
"discord-api-types": "^0.37.114"
|
||||
"discord-api-types": "^0.38.16"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@discordjs/api-extractor": "workspace:^",
|
||||
|
||||
@@ -223,9 +223,13 @@ export class ChannelsAPI {
|
||||
public async edit(
|
||||
channelId: Snowflake,
|
||||
body: RESTPatchAPIChannelJSONBody,
|
||||
{ signal }: Pick<RequestData, 'signal'> = {},
|
||||
{ signal, reason }: Pick<RequestData, 'reason' | 'signal'> = {},
|
||||
) {
|
||||
return this.rest.patch(Routes.channel(channelId), { body, signal }) as Promise<RESTPatchAPIChannelResult>;
|
||||
return this.rest.patch(Routes.channel(channelId), {
|
||||
reason,
|
||||
body,
|
||||
signal,
|
||||
}) as Promise<RESTPatchAPIChannelResult>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -235,8 +239,8 @@ export class ChannelsAPI {
|
||||
* @param channelId - The id of the channel to delete
|
||||
* @param options - The options for deleting the channel
|
||||
*/
|
||||
public async delete(channelId: Snowflake, { signal }: Pick<RequestData, 'signal'> = {}) {
|
||||
return this.rest.delete(Routes.channel(channelId), { signal }) as Promise<RESTDeleteAPIChannelResult>;
|
||||
public async delete(channelId: Snowflake, { signal, reason }: Pick<RequestData, 'reason' | 'signal'> = {}) {
|
||||
return this.rest.delete(Routes.channel(channelId), { signal, reason }) as Promise<RESTDeleteAPIChannelResult>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -441,11 +445,12 @@ export class ChannelsAPI {
|
||||
channelId: Snowflake,
|
||||
body: RESTPostAPIChannelThreadsJSONBody,
|
||||
messageId?: Snowflake,
|
||||
{ signal }: Pick<RequestData, 'signal'> = {},
|
||||
{ signal, reason }: Pick<RequestData, 'reason' | 'signal'> = {},
|
||||
) {
|
||||
return this.rest.post(Routes.threads(channelId, messageId), {
|
||||
body,
|
||||
signal,
|
||||
reason,
|
||||
}) as Promise<RESTPostAPIChannelThreadsResult>;
|
||||
}
|
||||
|
||||
@@ -460,7 +465,7 @@ export class ChannelsAPI {
|
||||
public async createForumThread(
|
||||
channelId: Snowflake,
|
||||
{ message, ...optionsBody }: StartForumThreadOptions,
|
||||
{ signal }: Pick<RequestData, 'signal'> = {},
|
||||
{ signal, reason }: Pick<RequestData, 'reason' | 'signal'> = {},
|
||||
) {
|
||||
const { files, ...messageBody } = message;
|
||||
|
||||
@@ -469,7 +474,12 @@ export class ChannelsAPI {
|
||||
message: messageBody,
|
||||
};
|
||||
|
||||
return this.rest.post(Routes.threads(channelId), { files, body, signal }) as Promise<APIThreadChannel>;
|
||||
return this.rest.post(Routes.threads(channelId), {
|
||||
files,
|
||||
body,
|
||||
reason,
|
||||
signal,
|
||||
}) as Promise<APIThreadChannel>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -115,7 +115,7 @@ export class GuildsAPI {
|
||||
* @param options - The options for fetching the guild
|
||||
* @deprecated Use the overload with a query instead.
|
||||
*/
|
||||
public async get(guildId: Snowflake, { signal }?: Pick<RequestData, 'signal'>): Promise<RESTGetAPIGuildResult>;
|
||||
public async get(guildId: Snowflake, { signal }: Pick<RequestData, 'signal'>): Promise<RESTGetAPIGuildResult>;
|
||||
|
||||
/**
|
||||
* Fetches a guild
|
||||
@@ -198,8 +198,8 @@ export class GuildsAPI {
|
||||
* @param guildId - The id of the guild to delete
|
||||
* @param options - The options for deleting this guild
|
||||
*/
|
||||
public async delete(guildId: Snowflake, { signal, reason }: Pick<RequestData, 'reason' | 'signal'> = {}) {
|
||||
await this.rest.delete(Routes.guild(guildId), { reason, signal });
|
||||
public async delete(guildId: Snowflake, { signal }: Pick<RequestData, 'signal'> = {}) {
|
||||
await this.rest.delete(Routes.guild(guildId), { signal });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -44,7 +44,7 @@ export class OAuth2API {
|
||||
{ signal }: Pick<RequestData, 'signal'> = {},
|
||||
) {
|
||||
return this.rest.post(Routes.oauth2TokenExchange(), {
|
||||
body: makeURLSearchParams(body),
|
||||
body: makeURLSearchParams<RESTPostOAuth2AccessTokenURLEncodedData>(body),
|
||||
passThroughBody: true,
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
@@ -66,7 +66,7 @@ export class OAuth2API {
|
||||
{ signal }: Pick<RequestData, 'signal'> = {},
|
||||
) {
|
||||
return this.rest.post(Routes.oauth2TokenExchange(), {
|
||||
body: makeURLSearchParams(body),
|
||||
body: makeURLSearchParams<RESTPostOAuth2RefreshTokenURLEncodedData>(body),
|
||||
passThroughBody: true,
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
type RESTPatchAPIWebhookJSONBody,
|
||||
type RESTPatchAPIWebhookResult,
|
||||
type RESTPatchAPIWebhookWithTokenMessageJSONBody,
|
||||
type RESTPatchAPIWebhookWithTokenMessageQuery,
|
||||
type RESTPatchAPIWebhookWithTokenMessageResult,
|
||||
type RESTPostAPIWebhookWithTokenGitHubQuery,
|
||||
type RESTPostAPIWebhookWithTokenJSONBody,
|
||||
@@ -127,13 +128,14 @@ export class WebhooksAPI {
|
||||
{
|
||||
wait,
|
||||
thread_id,
|
||||
with_components,
|
||||
files,
|
||||
...body
|
||||
}: RESTPostAPIWebhookWithTokenJSONBody & RESTPostAPIWebhookWithTokenQuery & { files?: RawFile[] },
|
||||
{ signal }: Pick<RequestData, 'signal'> = {},
|
||||
) {
|
||||
return this.rest.post(Routes.webhook(id, token), {
|
||||
query: makeURLSearchParams({ wait, thread_id }),
|
||||
query: makeURLSearchParams({ wait, thread_id, with_components }),
|
||||
files,
|
||||
body,
|
||||
auth: false,
|
||||
@@ -232,13 +234,14 @@ export class WebhooksAPI {
|
||||
messageId: Snowflake,
|
||||
{
|
||||
thread_id,
|
||||
with_components,
|
||||
files,
|
||||
...body
|
||||
}: RESTPatchAPIWebhookWithTokenMessageJSONBody & { files?: RawFile[]; thread_id?: string },
|
||||
}: RESTPatchAPIWebhookWithTokenMessageJSONBody & RESTPatchAPIWebhookWithTokenMessageQuery & { files?: RawFile[] },
|
||||
{ signal }: Pick<RequestData, 'signal'> = {},
|
||||
) {
|
||||
return this.rest.patch(Routes.webhookMessage(id, token, messageId), {
|
||||
query: makeURLSearchParams({ thread_id }),
|
||||
query: makeURLSearchParams({ thread_id, with_components }),
|
||||
auth: false,
|
||||
body,
|
||||
signal,
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<p>
|
||||
<a href="https://discord.gg/djs"><img src="https://img.shields.io/discord/222078108977594368?color=5865F2&logo=discord&logoColor=white" alt="Discord server" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Build status" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/commits/main/packages/create-discord-bot"><img alt="Last commit." src="https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fcreate-discord-bot"></a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://vercel.com/?utm_source=discordjs&utm_campaign=oss"><img src="https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg" alt="Vercel" /></a>
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
"no-void": "error",
|
||||
"no-warning-comments": "warn",
|
||||
"prefer-promise-reject-errors": "error",
|
||||
"require-await": "warn",
|
||||
"require-await": "off",
|
||||
"wrap-iife": "error",
|
||||
"yoda": "error",
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/lintstagedrc.schema.json",
|
||||
"*": "prettier --ignore-unknown --write",
|
||||
"{src/**,test/**,typings/**,scripts/**}.{mjs,js,ts}": "cross-env ESLINT_USE_FLAT_CONFIG=false eslint --ext mjs,js,ts --fix"
|
||||
"{src/**,typings/**,scripts/**}.{mjs,js,ts}": "cross-env ESLINT_USE_FLAT_CONFIG=false eslint --ext mjs,js,ts --fix"
|
||||
}
|
||||
|
||||
@@ -2,6 +2,195 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
# [14.21.0](https://github.com/discordjs/discord.js/compare/14.20.0...14.21.0) - (2025-06-25)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **ClientUser:** Remove token assignment (#10953) ([507b696](https://github.com/discordjs/discord.js/commit/507b696792d61ae49565b4613439aceb08dcf38a))
|
||||
|
||||
## Features
|
||||
|
||||
- **GuildMember:** Add `avatarDecorationData` (#10942) ([15f7571](https://github.com/discordjs/discord.js/commit/15f7571243d5b206141290478fd5164d299c0850))
|
||||
- **ClientApplication:** Add `approximateUserAuthorizationCount` (#10933) ([3fa429c](https://github.com/discordjs/discord.js/commit/3fa429c7dfa3bb3e6f099cd2f068c474a01677b1))
|
||||
|
||||
## Typings
|
||||
|
||||
- **ClientEventTypes:** Add missing `guildSoundboardSoundsUpdate` (#10928) ([c2a43b6](https://github.com/discordjs/discord.js/commit/c2a43b685e01eff878a399e8c00df8e473c185ad))
|
||||
|
||||
# [14.20.0](https://github.com/discordjs/discord.js/compare/14.19.3...14.20.0) - (2025-06-16)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- Use resolvePartialEmoji on MessagePayload#options#components (#10910) ([f2f757c](https://github.com/discordjs/discord.js/commit/f2f757ce52b76d5e571f47f9bf1c5188627b80d5))
|
||||
- **ChannelManager:** Remove threads from cache upon deletion (#10883) ([ee2eb73](https://github.com/discordjs/discord.js/commit/ee2eb7349f2467451880baaea54e02074916015f))
|
||||
- **PartialGroupDMChannel:** Prevent `undefined` values (#10889) ([9bca4af](https://github.com/discordjs/discord.js/commit/9bca4af5fdb78fae7b970498db7f93df31f55ef9))
|
||||
|
||||
## Features
|
||||
|
||||
- Backport entrypoint command (#10908) ([c0eae34](https://github.com/discordjs/discord.js/commit/c0eae344c2ed43fa67be9fda8e3d3e479693d2d1))
|
||||
- **BaseInteraction:** Add `attachmentSizeLimit` (#10830) ([7e21a94](https://github.com/discordjs/discord.js/commit/7e21a9474e532c5b22c6e0600c446fca47352617))
|
||||
|
||||
## Performance
|
||||
|
||||
- **Components:** Hash table (#10893) ([2d19163](https://github.com/discordjs/discord.js/commit/2d19163d764705667691430e438499fd330ffb65))
|
||||
|
||||
## Refactor
|
||||
|
||||
- **Client:** Remove `with_expiration` query parameter (#10800) ([c8f6066](https://github.com/discordjs/discord.js/commit/c8f6066d6a0a1fc6ac23a49d66604d95b588af3e))
|
||||
|
||||
# [14.19.3](https://github.com/discordjs/discord.js/compare/14.19.2...14.19.3) - (2025-05-02)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- Regression in allowedMentions when replying (#10866) ([2ebb5cb](https://github.com/discordjs/discord.js/commit/2ebb5cbd53d869a52cba4549e7acc417963741cd))
|
||||
|
||||
# [14.19.2](https://github.com/discordjs/discord.js/compare/14.19.1...14.19.2) - (2025-04-28)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **WebSocketManager:** Always emit shardDisconnect on unresumable close (#10826) ([37ef57b](https://github.com/discordjs/discord.js/commit/37ef57b88079db2f87036dfd9d57af9a2e5d1b9f))
|
||||
- **SoundboardSound:** Wrong emoji comparison in `equals` (#10861) ([5f3fc17](https://github.com/discordjs/discord.js/commit/5f3fc170fbfd49fa4f117901578c309f00f65d0b))
|
||||
- AllowedMentions, container, media item `toJSON()` for components v2 (#10852) ([20fade2](https://github.com/discordjs/discord.js/commit/20fade2a875695aa677e32b983320e746fd4d69c))
|
||||
- **Guild:** Cache soundboard sounds when patching (#10857) ([e827644](https://github.com/discordjs/discord.js/commit/e827644b5aecf05f7551e4e31a620894cc7aa71f))
|
||||
- **GuildSoundboardSoundManager:** Value "undefined" is not snowflake (#10854) ([6281592](https://github.com/discordjs/discord.js/commit/62815928aba0baa96b3422a4a7f1c4321c123dc7))
|
||||
|
||||
## Typings
|
||||
|
||||
- **GuildSoundboardSoundEditOptions:** Add missing `reason` (#10863) ([e3c247e](https://github.com/discordjs/discord.js/commit/e3c247e423c91b9d9e1d40d0521b6eddf0bc53c9))
|
||||
|
||||
# [14.19.1](https://github.com/discordjs/discord.js/compare/14.19.0...14.19.1) - (2025-04-26)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- Add in `withComponents` to Webhook ([481ccd2](https://github.com/discordjs/discord.js/commit/481ccd228bc240e32ac552475f8427a8042e1add))
|
||||
|
||||
# [14.19.0](https://github.com/discordjs/discord.js/compare/14.18.0...14.19.0) - (2025-04-26)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- Set `with_components` when sending components through webhooks ([8cdbe23](https://github.com/discordjs/discord.js/commit/8cdbe23766c6e5fe1e0acc040120e839511fea2c))
|
||||
- **GuildAuditLogEntry:** Fix some incorrect types and runtime logic (#10849) ([d920933](https://github.com/discordjs/discord.js/commit/d920933dc5b3c518754f526a9864582fc2c92a43))
|
||||
- Spread out section components next to accessory ([1605a2c](https://github.com/discordjs/discord.js/commit/1605a2c2894c4bb834c604f13a5a91cdbffac3a8))
|
||||
- Correctly extend CachedManager in GuildSoundboardSoundManager ([532c384](https://github.com/discordjs/discord.js/commit/532c3842bc293c965dd9fee846257c9e0bbb450a))
|
||||
- **MessagePayload:** Preserve existing flags when editing (#10766) ([ebfd526](https://github.com/discordjs/discord.js/commit/ebfd52695e205bccda3ae6f4ec39d4e5e8891ab0))
|
||||
|
||||
## Features
|
||||
|
||||
- Soundboard missing things (#10850) ([2d817df](https://github.com/discordjs/discord.js/commit/2d817df3b5894da84a1990cb4e0cfded8a925e75))
|
||||
- Components v2 in v14 (#10781) ([edace17](https://github.com/discordjs/discord.js/commit/edace17a131f857547163a3acf4bb6fec0c1e415))
|
||||
- Add soundboard in v14 (#10843) ([d3154cf](https://github.com/discordjs/discord.js/commit/d3154cf8f1eb027b5b4921d4048a32f464a3cd85))
|
||||
|
||||
## Typings
|
||||
|
||||
- Make `Client.on()` compatible with esnext.disposable in TS5.6+ (#10773) ([45552fa](https://github.com/discordjs/discord.js/commit/45552faf02c67b5079f34567c0214203cd927d2e))
|
||||
|
||||
# [14.18.0](https://github.com/discordjs/discord.js/compare/14.17.3...14.18.0) - (2025-02-10)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **Guild:** Type error with permissionOverwrites (#10527) ([8e1e1be](https://github.com/discordjs/discord.js/commit/8e1e1be0c23a0a063a6b530ac8cee30cf7629644))
|
||||
- Incorrect relative path (#10734) ([b7f1ebc](https://github.com/discordjs/discord.js/commit/b7f1ebc334e110be3208c476b61b82a69386fd84))
|
||||
- **PresenceUpdate:** Correctly add user regardless of their properties (#10672) ([7c1b73c](https://github.com/discordjs/discord.js/commit/7c1b73cc697fd3b85011bdb2c098ca3a3f863b1f))
|
||||
- **InteractionResponses:** Mark replied true for followUps (#10688) ([32dff01](https://github.com/discordjs/discord.js/commit/32dff01f291271bde3cfb354964ed140a6fa82d7))
|
||||
|
||||
## Documentation
|
||||
|
||||
- Use link tags to render links on the documentation (#10731) ([66b9718](https://github.com/discordjs/discord.js/commit/66b971899ab702240642e3ae2d189fd9e7efc701))
|
||||
- **Message:** Improve message snapshots description (#10709) ([31df3d2](https://github.com/discordjs/discord.js/commit/31df3d21cdc53400672924bc7c5dc7fd3053630b))
|
||||
|
||||
## Features
|
||||
|
||||
- Message forwards (#10733) ([89c076c](https://github.com/discordjs/discord.js/commit/89c076c89e90e8f5912786e8899ced9e8eea6003))
|
||||
- Incident Actions (#10727) ([41dee51](https://github.com/discordjs/discord.js/commit/41dee5177d9cb15f667e60a34619882222bf249c))
|
||||
- **website:** Type parameters links, builtin doc links, default values (#10515) ([43235d4](https://github.com/discordjs/discord.js/commit/43235d43fe76e26805c52dcff13519652bcb6a4a))
|
||||
- **PartialGroupDMChannel:** Add missing properties (#10502) ([5e66f85](https://github.com/discordjs/discord.js/commit/5e66f85f55724a583921252b035eb2097345fec8))
|
||||
- **Subscription:** Add `renewalSkuIds` (#10662) ([efa50fc](https://github.com/discordjs/discord.js/commit/efa50fc3fa463b09bde11c1640daa2abb8c22686))
|
||||
- **website:** Include reexported members in docs (#10518) ([aa61c20](https://github.com/discordjs/discord.js/commit/aa61c20ffdac3f3a0dca224f9e48e614309ecb2e))
|
||||
|
||||
## Refactor
|
||||
|
||||
- Use throw instead of Promise.reject (#10712) ([2663d76](https://github.com/discordjs/discord.js/commit/2663d767099f2e14a23f9cbfb868f279ffb253d1))
|
||||
- Remove data resolver exports (#10701) ([4606041](https://github.com/discordjs/discord.js/commit/46060419a9593dc5132ba6f13b58d0c18613679b))
|
||||
- **IntegrationApplication:** Move common properties to Application (#10627) ([95db597](https://github.com/discordjs/discord.js/commit/95db597fc844e7951b07cfb5741e27086ac7451a))
|
||||
|
||||
## Styling
|
||||
|
||||
- Prettier ([92aea94](https://github.com/discordjs/discord.js/commit/92aea944119638b12c03be0f627f20fe5fe5145e))
|
||||
|
||||
## Typings
|
||||
|
||||
- Fix recurrence rule types (#10694) ([193a5e9](https://github.com/discordjs/discord.js/commit/193a5e9e20fc4832592b2a3b6f142752121f43d5))
|
||||
- **ThreadOnlyChannel:** Remove incorrect `messages` property (#10708) ([44a1e85](https://github.com/discordjs/discord.js/commit/44a1e858473a51809cb1e6114d6a659fe28587f0))
|
||||
- Add `undefined` to `flags` for `exactOptionalPropertyTypes` (#10707) ([d2e1924](https://github.com/discordjs/discord.js/commit/d2e1924fa6a06120879a1158d501a899db3d6d96))
|
||||
- Allow only ephemeral for defer reply (#10696) ([68dd260](https://github.com/discordjs/discord.js/commit/68dd260dee1a7b0bbd4fcdff1b39283ea8dcedec))
|
||||
- Remove createComponent and createComponentBuilder (#10687) ([0047a49](https://github.com/discordjs/discord.js/commit/0047a49b7395acf0936702f233e7fb89e9f352fe))
|
||||
|
||||
# [14.17.3](https://github.com/discordjs/discord.js/compare/14.17.2...14.17.3) - (2025-01-08)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **Message:** Ensure channel is defined for clean content (#10681) ([46bf8f0](https://github.com/discordjs/discord.js/commit/46bf8f0146b67d7c480a3512ade1edbfb16e7a26))
|
||||
- Use `resolve()` for `PermissionOverwrites` (#10686) ([7280d4e](https://github.com/discordjs/discord.js/commit/7280d4e82eb47ce7cb3964057d7d56a62179cf18))
|
||||
|
||||
# [14.17.2](https://github.com/discordjs/discord.js/compare/14.17.1...14.17.2) - (2025-01-02)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **InteractionResponses:** Check correct property for deprecation ([77804cf](https://github.com/discordjs/discord.js/commit/77804cfd559691d9b8c85aec8c494cd6c14c4ea7))
|
||||
|
||||
# [14.17.0](https://github.com/discordjs/discord.js/compare/14.16.3...14.17.0) - (2025-01-01)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **InteractionResponses:** Do not use `in` if a string is passed ([ff42d7a](https://github.com/discordjs/discord.js/commit/ff42d7af72e940ae72c61d2c5164ae68f2708b96))
|
||||
- Use Message#interactionMetadata (#10654) ([6087088](https://github.com/discordjs/discord.js/commit/60870885790eb1857ed4c2969c9c404e356a1299))
|
||||
- **InteractionResponses:** Properly resolve message flags (#10661) ([b2754d4](https://github.com/discordjs/discord.js/commit/b2754d4a0ec250ae84057d0f07c078376f54829c))
|
||||
- **ThreadChannel:** Make `ownerId` always present (#10618) ([7678f11](https://github.com/discordjs/discord.js/commit/7678f1176a645878261361faef0429f9cf7f4810))
|
||||
- **MessageReaction:** Address `undefined` burst properties (#10597) ([76968b4](https://github.com/discordjs/discord.js/commit/76968b4bc14b8a66825f9140d130b1e04c11855a))
|
||||
- **ThreadChannel:** Address parameter type on fetchOwner() (#10592) ([56c9396](https://github.com/discordjs/discord.js/commit/56c9396b717d4dec2410ca13938ce238ec21215d))
|
||||
- **InteractionResponses:** Throw error on deleting response of unacknowledged interaction (#10587) ([21c283f](https://github.com/discordjs/discord.js/commit/21c283f964ab9e331db53cc0c21ca64980372488))
|
||||
- **GuildScheduledEvent:** Handle null recurrence_rule (#10543) ([831aafa](https://github.com/discordjs/discord.js/commit/831aafa733e8eea55534c4c39b87775d2e2f56c4))
|
||||
|
||||
## Documentation
|
||||
|
||||
- Correct discord-api-types URLs (#10622) ([76042f0](https://github.com/discordjs/discord.js/commit/76042f05386edcbadc5ad4ded22e8b15c7b6f8ec))
|
||||
- Typos (#10628) ([388783d](https://github.com/discordjs/discord.js/commit/388783d7dd718aae519801b90aa781d07b7fb64e))
|
||||
- Add note about idempotence to role add/remove routes (#10586) ([565fc01](https://github.com/discordjs/discord.js/commit/565fc0192a5ed2642ff1bd615c59678b5c3cd24b))
|
||||
- **Client:** Fix incorrect managers descriptions ([f79ba52](https://github.com/discordjs/discord.js/commit/f79ba52c7a1334d987e9873a8a411e92d5140116))
|
||||
- **discord.js:** Remove `utf-8-validate` (#10531) ([297e959](https://github.com/discordjs/discord.js/commit/297e959f48abbfd3af58cc29cdcef139d3579821))
|
||||
|
||||
## Features
|
||||
|
||||
- **ClientApplication:** Add webhook events (#10588) ([7b2a2e3](https://github.com/discordjs/discord.js/commit/7b2a2e3a154afd69ff892da615ea75c46730f226))
|
||||
- **InteractionResponses:** Support `with_response` query parameter (#10636) ([622acbc](https://github.com/discordjs/discord.js/commit/622acbcbf02c3b8e0eae4296964c3e745e19378d))
|
||||
- **ClientApplication:** Add webhook events (#10588) ([ae1deac](https://github.com/discordjs/discord.js/commit/ae1deac2bf37aecda4c044bf5c28d03930bd763b))
|
||||
- **EntitlementManager:** Support get entitlement (#10606) ([a367e2c](https://github.com/discordjs/discord.js/commit/a367e2c8c99ab3bfb83cdbfb65e7a5020b50b7f7))
|
||||
- Add subscriptions (#10541) ([4cca33d](https://github.com/discordjs/discord.js/commit/4cca33d9b0759294c9a2dfec39d80a24a2cc1595))
|
||||
- Emit reaction type on gateway events (#10598) ([bda3128](https://github.com/discordjs/discord.js/commit/bda31284bf46515747e002e86ea35d0b6910e269))
|
||||
- Voice Channel Effect Send (#10318) ([34343c6](https://github.com/discordjs/discord.js/commit/34343c6afae65205d3b17b60fdd202d0937d6a46))
|
||||
- **GuildMember:** Banners (#10384) ([b1ded63](https://github.com/discordjs/discord.js/commit/b1ded63e42e7349f535df4680509b9393dd8f288))
|
||||
- Add ApplicationEmoji to EmojiResolvable and MessageReaction#emoji (#10477) ([1fc87a9](https://github.com/discordjs/discord.js/commit/1fc87a96987fe69722502d7574500926a4e0bfde))
|
||||
- Recurring scheduled events (#10447) ([97c3237](https://github.com/discordjs/discord.js/commit/97c3237a70027f71bb3f046357a55bb730daca14))
|
||||
- Message forwarding (#10464) ([c122178](https://github.com/discordjs/discord.js/commit/c12217829b46f7a60266f65af4af19cdbfcd7906))
|
||||
|
||||
## Refactor
|
||||
|
||||
- **FetchApplicationCommandOptions:** Use `Locale` over `LocaleString` (#10625) ([7ce6f2f](https://github.com/discordjs/discord.js/commit/7ce6f2fc8a8756532d71a542186d10a0aa951471))
|
||||
- Use `cache.get()` for snowflakes, `resolve()` otherwise (#10626) ([dedaa5d](https://github.com/discordjs/discord.js/commit/dedaa5d657f15491910ec05102ce72affc822b97))
|
||||
- Remove extra traversing (#10580) ([33533b7](https://github.com/discordjs/discord.js/commit/33533b72849d9741dae8c979734b45abbf3657a7))
|
||||
- **InteractionResponses:** Deprecate ephemeral response option (#10574) ([be38f57](https://github.com/discordjs/discord.js/commit/be38f5792602ed1a79a9638aa8e629e7ad6bdd0d))
|
||||
- Deprecate `reason` parameter on adding and removing thread members (#10551) ([72e0c99](https://github.com/discordjs/discord.js/commit/72e0c994547f2a9c99b320870e14d7f1643f3851))
|
||||
- Deprecate fetching user flags (#10550) ([3d06c9d](https://github.com/discordjs/discord.js/commit/3d06c9d872b2e79356f1239f7d0eb0577a4bcedf))
|
||||
|
||||
## Testing
|
||||
|
||||
- Remove unused test (#10638) ([53cbb0e](https://github.com/discordjs/discord.js/commit/53cbb0e36d4ab191cbc15a022d752da14c2e0ace))
|
||||
|
||||
## Typings
|
||||
|
||||
- Add missing `Caches` managers (#10540) ([13471fa](https://github.com/discordjs/discord.js/commit/13471fa1b7c44b236db9fe9b1a64dacd41b14b76))
|
||||
- Remove newMessage partial on messageUpdate event typing (#10526) ([5faf074](https://github.com/discordjs/discord.js/commit/5faf074c145044f0edefafab97fd07a8dfb8bc30))
|
||||
|
||||
# [14.16.3](https://github.com/discordjs/discord.js/compare/14.16.2...14.16.3) - (2024-09-29)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
<a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/v/discord.js.svg?maxAge=3600" alt="npm version" /></a>
|
||||
<a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/dt/discord.js.svg?maxAge=3600" alt="npm downloads" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Tests status" /></a>
|
||||
<a href="https://codecov.io/gh/discordjs/discord.js" ><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2" alt="Code coverage" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/commits/main/packages/discord.js"><img alt="Last commit." src="https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fdiscord.js"></a>
|
||||
<a href="https://codecov.io/gh/discordjs/discord.js"><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2" alt="Code coverage" /></a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://vercel.com/?utm_source=discordjs&utm_campaign=oss"><img src="https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg" alt="Vercel" /></a>
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
{
|
||||
"extends": "../../api-extractor.json",
|
||||
"mainEntryPointFilePath": "<projectFolder>/typings/index.d.ts",
|
||||
"bundledPackages": [
|
||||
"discord-api-types",
|
||||
"@discordjs/builders",
|
||||
"@discordjs/formatters",
|
||||
"@discordjs/rest",
|
||||
"@discordjs/util",
|
||||
"@discordjs/ws"
|
||||
],
|
||||
"docModel": {
|
||||
"projectFolderUrl": "https://github.com/discordjs/discord.js/tree/main/packages/discord.js"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "discord.js",
|
||||
"version": "14.16.3",
|
||||
"version": "14.21.0",
|
||||
"description": "A powerful library for interacting with the Discord API",
|
||||
"scripts": {
|
||||
"test": "pnpm run docs:test && pnpm run test:typescript",
|
||||
@@ -36,7 +36,8 @@
|
||||
},
|
||||
"files": [
|
||||
"src",
|
||||
"typings"
|
||||
"typings/*.d.ts",
|
||||
"typings/*.d.mts"
|
||||
],
|
||||
"contributors": [
|
||||
"Crawl <icrawltogo@gmail.com>",
|
||||
@@ -65,18 +66,19 @@
|
||||
"homepage": "https://discord.js.org",
|
||||
"funding": "https://github.com/discordjs/discord.js?sponsor",
|
||||
"dependencies": {
|
||||
"@discordjs/builders": "^1.10.0",
|
||||
"@discordjs/builders": "^1.11.2",
|
||||
"@discordjs/collection": "1.5.3",
|
||||
"@discordjs/formatters": "^0.6.0",
|
||||
"@discordjs/formatters": "^0.6.1",
|
||||
"@discordjs/rest": "workspace:^",
|
||||
"@discordjs/util": "workspace:^",
|
||||
"@discordjs/ws": "^1.1.1",
|
||||
"@discordjs/ws": "^1.2.3",
|
||||
"@sapphire/snowflake": "3.5.3",
|
||||
"discord-api-types": "^0.37.114",
|
||||
"discord-api-types": "^0.38.16",
|
||||
"fast-deep-equal": "3.1.3",
|
||||
"lodash.snakecase": "4.1.1",
|
||||
"magic-bytes.js": "^1.10.0",
|
||||
"tslib": "^2.6.3",
|
||||
"undici": "6.19.8"
|
||||
"undici": "6.21.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@discordjs/api-extractor": "workspace:^",
|
||||
|
||||
@@ -18,6 +18,7 @@ const ClientPresence = require('../structures/ClientPresence');
|
||||
const GuildPreview = require('../structures/GuildPreview');
|
||||
const GuildTemplate = require('../structures/GuildTemplate');
|
||||
const Invite = require('../structures/Invite');
|
||||
const { SoundboardSound } = require('../structures/SoundboardSound');
|
||||
const { Sticker } = require('../structures/Sticker');
|
||||
const StickerPack = require('../structures/StickerPack');
|
||||
const VoiceRegion = require('../structures/VoiceRegion');
|
||||
@@ -276,7 +277,6 @@ class Client extends BaseClient {
|
||||
const code = resolveInviteCode(invite);
|
||||
const query = makeURLSearchParams({
|
||||
with_counts: true,
|
||||
with_expiration: true,
|
||||
guild_scheduled_event_id: options?.guildScheduledEventId,
|
||||
});
|
||||
const data = await this.rest.get(Routes.invite(code), { query });
|
||||
@@ -390,6 +390,19 @@ class Client extends BaseClient {
|
||||
return this.fetchStickerPacks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the list of default soundboard sounds.
|
||||
* @returns {Promise<Collection<string, SoundboardSound>>}
|
||||
* @example
|
||||
* client.fetchDefaultSoundboardSounds()
|
||||
* .then(sounds => console.log(`Available soundboard sounds are: ${sounds.map(sound => sound.name).join(', ')}`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async fetchDefaultSoundboardSounds() {
|
||||
const data = await this.rest.get(Routes.soundboardDefaultSounds());
|
||||
return new Collection(data.map(sound => [sound.sound_id, new SoundboardSound(this, sound)]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a guild preview from Discord, available for all guilds the bot is in and all Discoverable guilds.
|
||||
* @param {GuildResolvable} guild The guild to fetch the preview for
|
||||
@@ -509,7 +522,7 @@ class Client extends BaseClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval} on a script
|
||||
* Calls {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/eval} on a script
|
||||
* with the client as `this`.
|
||||
* @param {string} script Script to eval
|
||||
* @returns {*}
|
||||
@@ -591,7 +604,7 @@ module.exports = Client;
|
||||
*/
|
||||
|
||||
/**
|
||||
* A {@link https://developer.twitter.com/en/docs/twitter-ids Twitter snowflake},
|
||||
* A {@link https://docs.x.com/resources/fundamentals/x-ids Twitter snowflake},
|
||||
* except the epoch is 2015-01-01T00:00:00.000Z.
|
||||
*
|
||||
* If we have a snowflake '266241948824764416' we can represent it as binary:
|
||||
@@ -625,6 +638,11 @@ module.exports = Client;
|
||||
* @see {@link https://discord.js.org/docs/packages/rest/stable/ImageURLOptions:Interface}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external EmojiURLOptions
|
||||
* @see {@link https://discord.js.org/docs/packages/rest/stable/EmojiURLOptions:TypeAlias}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external BaseImageURLOptions
|
||||
* @see {@link https://discord.js.org/docs/packages/rest/stable/BaseImageURLOptions:Interface}
|
||||
|
||||
@@ -112,6 +112,10 @@ class GenericAction {
|
||||
return this.getPayload({ user_id: id }, manager, id, Partials.ThreadMember, false);
|
||||
}
|
||||
|
||||
getSoundboardSound(data, guild) {
|
||||
return this.getPayload(data, guild.soundboardSounds, data.sound_id, Partials.SoundboardSound);
|
||||
}
|
||||
|
||||
spreadInjectedData(data) {
|
||||
return Object.fromEntries(Object.getOwnPropertySymbols(data).map(symbol => [symbol, data[symbol]]));
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ class ActionsManager {
|
||||
this.register(require('./GuildScheduledEventUpdate'));
|
||||
this.register(require('./GuildScheduledEventUserAdd'));
|
||||
this.register(require('./GuildScheduledEventUserRemove'));
|
||||
this.register(require('./GuildSoundboardSoundDelete.js'));
|
||||
this.register(require('./GuildStickerCreate'));
|
||||
this.register(require('./GuildStickerDelete'));
|
||||
this.register(require('./GuildStickerUpdate'));
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
const Action = require('./Action.js');
|
||||
const Events = require('../../util/Events.js');
|
||||
|
||||
class GuildSoundboardSoundDeleteAction extends Action {
|
||||
handle(data) {
|
||||
const guild = this.client.guilds.cache.get(data.guild_id);
|
||||
|
||||
if (!guild) return {};
|
||||
|
||||
const soundboardSound = this.getSoundboardSound(data, guild);
|
||||
|
||||
if (soundboardSound) {
|
||||
guild.soundboardSounds.cache.delete(soundboardSound.soundId);
|
||||
|
||||
/**
|
||||
* Emitted whenever a soundboard sound is deleted in a guild.
|
||||
* @event Client#guildSoundboardSoundDelete
|
||||
* @param {SoundboardSound} soundboardSound The soundboard sound that was deleted
|
||||
*/
|
||||
this.client.emit(Events.GuildSoundboardSoundDelete, soundboardSound);
|
||||
}
|
||||
|
||||
return { soundboardSound };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GuildSoundboardSoundDeleteAction;
|
||||
@@ -9,6 +9,7 @@ const ChatInputCommandInteraction = require('../../structures/ChatInputCommandIn
|
||||
const MentionableSelectMenuInteraction = require('../../structures/MentionableSelectMenuInteraction');
|
||||
const MessageContextMenuCommandInteraction = require('../../structures/MessageContextMenuCommandInteraction');
|
||||
const ModalSubmitInteraction = require('../../structures/ModalSubmitInteraction');
|
||||
const PrimaryEntryPointCommandInteraction = require('../../structures/PrimaryEntryPointCommandInteraction');
|
||||
const RoleSelectMenuInteraction = require('../../structures/RoleSelectMenuInteraction');
|
||||
const StringSelectMenuInteraction = require('../../structures/StringSelectMenuInteraction');
|
||||
const UserContextMenuCommandInteraction = require('../../structures/UserContextMenuCommandInteraction');
|
||||
@@ -38,6 +39,9 @@ class InteractionCreateAction extends Action {
|
||||
if (channel && !channel.isTextBased()) return;
|
||||
InteractionClass = MessageContextMenuCommandInteraction;
|
||||
break;
|
||||
case ApplicationCommandType.PrimaryEntryPoint:
|
||||
InteractionClass = PrimaryEntryPointCommandInteraction;
|
||||
break;
|
||||
default:
|
||||
client.emit(
|
||||
Events.Debug,
|
||||
|
||||
@@ -2,11 +2,14 @@
|
||||
|
||||
const Action = require('./Action');
|
||||
const Events = require('../../util/Events');
|
||||
const Partials = require('../../util/Partials');
|
||||
|
||||
class PresenceUpdateAction extends Action {
|
||||
handle(data) {
|
||||
let user = this.client.users.cache.get(data.user.id);
|
||||
if (!user && data.user.username) user = this.client.users._add(data.user);
|
||||
if (!user && ('username' in data.user || this.client.options.partials.includes(Partials.User))) {
|
||||
user = this.client.users._add(data.user);
|
||||
}
|
||||
if (!user) return;
|
||||
|
||||
if (data.user.username) {
|
||||
|
||||
@@ -19,6 +19,7 @@ const Status = require('../../util/Status');
|
||||
const WebSocketShardEvents = require('../../util/WebSocketShardEvents');
|
||||
|
||||
let zlib;
|
||||
let deprecationEmitted = false;
|
||||
|
||||
try {
|
||||
zlib = require('zlib-sync');
|
||||
@@ -36,10 +37,13 @@ const BeforeReadyWhitelist = [
|
||||
|
||||
const WaitingForGuildEvents = [GatewayDispatchEvents.GuildCreate, GatewayDispatchEvents.GuildDelete];
|
||||
|
||||
const UNRESUMABLE_CLOSE_CODES = [
|
||||
CloseCodes.Normal,
|
||||
GatewayCloseCodes.AlreadyAuthenticated,
|
||||
GatewayCloseCodes.InvalidSeq,
|
||||
const UNRECOVERABLE_CLOSE_CODES = [
|
||||
GatewayCloseCodes.AuthenticationFailed,
|
||||
GatewayCloseCodes.InvalidShard,
|
||||
GatewayCloseCodes.ShardingRequired,
|
||||
GatewayCloseCodes.InvalidAPIVersion,
|
||||
GatewayCloseCodes.InvalidIntents,
|
||||
GatewayCloseCodes.DisallowedIntents,
|
||||
];
|
||||
|
||||
const reasonIsDeprecated = 'the reason property is deprecated, use the code property to determine the reason';
|
||||
@@ -242,7 +246,7 @@ class WebSocketManager extends EventEmitter {
|
||||
this._ws.on(WSWebSocketShardEvents.Closed, ({ code, shardId }) => {
|
||||
const shard = this.shards.get(shardId);
|
||||
shard.emit(WebSocketShardEvents.Close, { code, reason: reasonIsDeprecated, wasClean: true });
|
||||
if (UNRESUMABLE_CLOSE_CODES.includes(code) && this.destroyed) {
|
||||
if (UNRECOVERABLE_CLOSE_CODES.includes(code)) {
|
||||
shard.status = Status.Disconnected;
|
||||
/**
|
||||
* Emitted when a shard's WebSocket disconnects and will no longer reconnect.
|
||||
@@ -251,7 +255,7 @@ class WebSocketManager extends EventEmitter {
|
||||
* @param {number} id The shard id that disconnected
|
||||
*/
|
||||
this.client.emit(Events.ShardDisconnect, { code, reason: reasonIsDeprecated, wasClean: true }, shardId);
|
||||
this.debug([`Shard not resumable: ${code} (${GatewayCloseCodes[code] ?? CloseCodes[code]})`], shardId);
|
||||
this.debug([`Shard not recoverable: ${code} (${GatewayCloseCodes[code] ?? CloseCodes[code]})`], shardId);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -376,6 +380,22 @@ class WebSocketManager extends EventEmitter {
|
||||
/**
|
||||
* Emitted when the client becomes ready to start working.
|
||||
* @event Client#ready
|
||||
* @deprecated Use {@link Client#event:clientReady} instead.
|
||||
* @param {Client} client The client
|
||||
*/
|
||||
if (this.client.emit('ready', this.client) && !deprecationEmitted) {
|
||||
deprecationEmitted = true;
|
||||
|
||||
process.emitWarning(
|
||||
// eslint-disable-next-line max-len
|
||||
'The ready event has been renamed to clientReady to distinguish it from the gateway READY event and will only emit under that name in v15. Please use clientReady instead.',
|
||||
'DeprecationWarning',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted when the client becomes ready to start working.
|
||||
* @event Client#clientReady
|
||||
* @param {Client} client The client
|
||||
*/
|
||||
this.client.emit(Events.ClientReady, this.client);
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
'use strict';
|
||||
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const Events = require('../../../util/Events.js');
|
||||
|
||||
module.exports = (client, { d: data }) => {
|
||||
const guild = client.guilds.cache.get(data.guild_id);
|
||||
|
||||
if (!guild) return;
|
||||
|
||||
const soundboardSounds = new Collection();
|
||||
|
||||
for (const soundboardSound of data.soundboard_sounds) {
|
||||
soundboardSounds.set(soundboardSound.sound_id, guild.soundboardSounds._add(soundboardSound));
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever multiple guild soundboard sounds are updated.
|
||||
* @event Client#guildSoundboardSoundsUpdate
|
||||
* @param {Collection<Snowflake, SoundboardSound>} soundboardSounds The updated soundboard sounds
|
||||
* @param {Guild} guild The guild that the soundboard sounds are from
|
||||
*/
|
||||
client.emit(Events.GuildSoundboardSoundsUpdate, soundboardSounds, guild);
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
const Events = require('../../../util/Events.js');
|
||||
|
||||
module.exports = (client, { d: data }) => {
|
||||
const guild = client.guilds.cache.get(data.guild_id);
|
||||
|
||||
if (!guild) return;
|
||||
|
||||
const soundboardSound = guild.soundboardSounds._add(data);
|
||||
|
||||
/**
|
||||
* Emitted whenever a guild soundboard sound is created.
|
||||
* @event Client#guildSoundboardSoundCreate
|
||||
* @param {SoundboardSound} soundboardSound The created guild soundboard sound
|
||||
*/
|
||||
client.emit(Events.GuildSoundboardSoundCreate, soundboardSound);
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = (client, { d: data }) => {
|
||||
client.actions.GuildSoundboardSoundDelete.handle(data);
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
const Events = require('../../../util/Events.js');
|
||||
|
||||
module.exports = (client, { d: data }) => {
|
||||
const guild = client.guilds.cache.get(data.guild_id);
|
||||
|
||||
if (!guild) return;
|
||||
|
||||
const oldGuildSoundboardSound = guild.soundboardSounds.cache.get(data.sound_id)?._clone() ?? null;
|
||||
const newGuildSoundboardSound = guild.soundboardSounds._add(data);
|
||||
|
||||
/**
|
||||
* Emitted whenever a guild soundboard sound is updated.
|
||||
* @event Client#guildSoundboardSoundUpdate
|
||||
* @param {?SoundboardSound} oldGuildSoundboardSound The guild soundboard sound before the update
|
||||
* @param {SoundboardSound} newGuildSoundboardSound The guild soundboard sound after the update
|
||||
*/
|
||||
client.emit(Events.GuildSoundboardSoundUpdate, oldGuildSoundboardSound, newGuildSoundboardSound);
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
'use strict';
|
||||
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const Events = require('../../../util/Events.js');
|
||||
|
||||
module.exports = (client, { d: data }) => {
|
||||
const guild = client.guilds.cache.get(data.guild_id);
|
||||
|
||||
if (!guild) return;
|
||||
|
||||
const soundboardSounds = new Collection();
|
||||
|
||||
for (const soundboardSound of data.soundboard_sounds) {
|
||||
soundboardSounds.set(soundboardSound.sound_id, guild.soundboardSounds._add(soundboardSound));
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever soundboard sounds are received (all soundboard sounds come from the same guild).
|
||||
* @event Client#soundboardSounds
|
||||
* @param {Collection<Snowflake, SoundboardSound>} soundboardSounds The sounds received
|
||||
* @param {Guild} guild The guild that the soundboard sounds are from
|
||||
*/
|
||||
client.emit(Events.SoundboardSounds, soundboardSounds, guild);
|
||||
};
|
||||
@@ -32,6 +32,10 @@ const handlers = Object.fromEntries([
|
||||
['GUILD_SCHEDULED_EVENT_UPDATE', require('./GUILD_SCHEDULED_EVENT_UPDATE')],
|
||||
['GUILD_SCHEDULED_EVENT_USER_ADD', require('./GUILD_SCHEDULED_EVENT_USER_ADD')],
|
||||
['GUILD_SCHEDULED_EVENT_USER_REMOVE', require('./GUILD_SCHEDULED_EVENT_USER_REMOVE')],
|
||||
['GUILD_SOUNDBOARD_SOUNDS_UPDATE', require('./GUILD_SOUNDBOARD_SOUNDS_UPDATE.js')],
|
||||
['GUILD_SOUNDBOARD_SOUND_CREATE', require('./GUILD_SOUNDBOARD_SOUND_CREATE.js')],
|
||||
['GUILD_SOUNDBOARD_SOUND_DELETE', require('./GUILD_SOUNDBOARD_SOUND_DELETE.js')],
|
||||
['GUILD_SOUNDBOARD_SOUND_UPDATE', require('./GUILD_SOUNDBOARD_SOUND_UPDATE.js')],
|
||||
['GUILD_STICKERS_UPDATE', require('./GUILD_STICKERS_UPDATE')],
|
||||
['GUILD_UPDATE', require('./GUILD_UPDATE')],
|
||||
['INTERACTION_CREATE', require('./INTERACTION_CREATE')],
|
||||
@@ -50,6 +54,7 @@ const handlers = Object.fromEntries([
|
||||
['PRESENCE_UPDATE', require('./PRESENCE_UPDATE')],
|
||||
['READY', require('./READY')],
|
||||
['RESUMED', require('./RESUMED')],
|
||||
['SOUNDBOARD_SOUNDS', require('./SOUNDBOARD_SOUNDS.js')],
|
||||
['STAGE_INSTANCE_CREATE', require('./STAGE_INSTANCE_CREATE')],
|
||||
['STAGE_INSTANCE_DELETE', require('./STAGE_INSTANCE_DELETE')],
|
||||
['STAGE_INSTANCE_UPDATE', require('./STAGE_INSTANCE_UPDATE')],
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
* @property {'GuildChannelUnowned'} GuildChannelUnowned
|
||||
* @property {'GuildOwned'} GuildOwned
|
||||
* @property {'GuildMembersTimeout'} GuildMembersTimeout
|
||||
* @property {'GuildSoundboardSoundsTimeout'} GuildSoundboardSoundsTimeout
|
||||
* @property {'GuildUncachedMe'} GuildUncachedMe
|
||||
* @property {'ChannelNotCached'} ChannelNotCached
|
||||
* @property {'StageChannelResolve'} StageChannelResolve
|
||||
@@ -131,6 +132,8 @@
|
||||
* @property {'MissingManageEmojisAndStickersPermission'} MissingManageEmojisAndStickersPermission
|
||||
* <warn>This property is deprecated. Use `MissingManageGuildExpressionsPermission` instead.</warn>
|
||||
*
|
||||
|
||||
* @property {'NotGuildSoundboardSound'} NotGuildSoundboardSound
|
||||
* @property {'NotGuildSticker'} NotGuildSticker
|
||||
|
||||
* @property {'ReactionResolveUser'} ReactionResolveUser
|
||||
@@ -266,6 +269,7 @@ const keys = [
|
||||
'GuildChannelUnowned',
|
||||
'GuildOwned',
|
||||
'GuildMembersTimeout',
|
||||
'GuildSoundboardSoundsTimeout',
|
||||
'GuildUncachedMe',
|
||||
'ChannelNotCached',
|
||||
'StageChannelResolve',
|
||||
@@ -290,6 +294,7 @@ const keys = [
|
||||
'MissingManageGuildExpressionsPermission',
|
||||
'MissingManageEmojisAndStickersPermission',
|
||||
|
||||
'NotGuildSoundboardSound',
|
||||
'NotGuildSticker',
|
||||
|
||||
'ReactionResolveUser',
|
||||
|
||||
@@ -91,11 +91,13 @@ const Messages = {
|
||||
[DjsErrorCodes.GuildChannelUnowned]: "The fetched channel does not belong to this manager's guild.",
|
||||
[DjsErrorCodes.GuildOwned]: 'Guild is owned by the client.',
|
||||
[DjsErrorCodes.GuildMembersTimeout]: "Members didn't arrive in time.",
|
||||
[DjsErrorCodes.GuildSoundboardSoundsTimeout]: "Soundboard sounds didn't arrive in time.",
|
||||
[DjsErrorCodes.GuildUncachedMe]: 'The client user as a member of this guild is uncached.',
|
||||
[DjsErrorCodes.ChannelNotCached]: 'Could not find the channel where this message came from in the cache!',
|
||||
[DjsErrorCodes.StageChannelResolve]: 'Could not resolve channel to a stage channel.',
|
||||
[DjsErrorCodes.GuildScheduledEventResolve]: 'Could not resolve the guild scheduled event.',
|
||||
[DjsErrorCodes.FetchOwnerId]: type => `Couldn't resolve the ${type} ownerId to fetch the ${type} member.`,
|
||||
[DjsErrorCodes.FetchOwnerId]: type =>
|
||||
`Couldn't resolve the ${type} ownerId to fetch the ${type} ${type === 'group DM' ? 'owner' : 'member'}.`,
|
||||
|
||||
[DjsErrorCodes.InvalidType]: (name, expected, an = false) => `Supplied ${name} is not a${an ? 'n' : ''} ${expected}.`,
|
||||
[DjsErrorCodes.InvalidElement]: (type, name, elem) => `Supplied ${type} ${name} includes an invalid element: ${elem}`,
|
||||
@@ -117,6 +119,8 @@ const Messages = {
|
||||
[DjsErrorCodes.MissingManageEmojisAndStickersPermission]: guild =>
|
||||
`Client must have Manage Emojis and Stickers permission in guild ${guild} to see emoji authors.`,
|
||||
|
||||
[DjsErrorCodes.NotGuildSoundboardSound]: action =>
|
||||
`Soundboard sound is a default (non-guild) soundboard sound and can't be ${action}.`,
|
||||
[DjsErrorCodes.NotGuildSticker]: 'Sticker is a standard (non-guild) sticker and has no author.',
|
||||
|
||||
[DjsErrorCodes.ReactionResolveUser]: "Couldn't resolve the user id to remove from the reaction.",
|
||||
|
||||
@@ -29,7 +29,6 @@ exports.ChannelFlagsBitField = require('./util/ChannelFlagsBitField');
|
||||
exports.Collection = require('@discordjs/collection').Collection;
|
||||
exports.Constants = require('./util/Constants');
|
||||
exports.Colors = require('./util/Colors');
|
||||
__exportStar(require('./util/DataResolver.js'), exports);
|
||||
exports.Events = require('./util/Events');
|
||||
exports.Formatters = require('./util/Formatters');
|
||||
exports.GuildMemberFlagsBitField = require('./util/GuildMemberFlagsBitField').GuildMemberFlagsBitField;
|
||||
@@ -76,6 +75,7 @@ exports.GuildMemberManager = require('./managers/GuildMemberManager');
|
||||
exports.GuildMemberRoleManager = require('./managers/GuildMemberRoleManager');
|
||||
exports.GuildMessageManager = require('./managers/GuildMessageManager');
|
||||
exports.GuildScheduledEventManager = require('./managers/GuildScheduledEventManager');
|
||||
exports.GuildSoundboardSoundManager = require('./managers/GuildSoundboardSoundManager.js').GuildSoundboardSoundManager;
|
||||
exports.GuildStickerManager = require('./managers/GuildStickerManager');
|
||||
exports.GuildTextThreadManager = require('./managers/GuildTextThreadManager');
|
||||
exports.MessageManager = require('./managers/MessageManager');
|
||||
@@ -124,12 +124,15 @@ exports.CommandInteraction = require('./structures/CommandInteraction');
|
||||
exports.Collector = require('./structures/interfaces/Collector');
|
||||
exports.CommandInteractionOptionResolver = require('./structures/CommandInteractionOptionResolver');
|
||||
exports.Component = require('./structures/Component');
|
||||
exports.ContainerComponent = require('./structures/ContainerComponent');
|
||||
exports.ContextMenuCommandInteraction = require('./structures/ContextMenuCommandInteraction');
|
||||
exports.DirectoryChannel = require('./structures/DirectoryChannel');
|
||||
exports.DMChannel = require('./structures/DMChannel');
|
||||
exports.Embed = require('./structures/Embed');
|
||||
exports.EmbedBuilder = require('./structures/EmbedBuilder');
|
||||
exports.Emoji = require('./structures/Emoji').Emoji;
|
||||
exports.Entitlement = require('./structures/Entitlement').Entitlement;
|
||||
exports.FileComponent = require('./structures/FileComponent');
|
||||
exports.ForumChannel = require('./structures/ForumChannel');
|
||||
exports.Guild = require('./structures/Guild').Guild;
|
||||
exports.GuildAuditLogs = require('./structures/GuildAuditLogs');
|
||||
@@ -162,6 +165,8 @@ exports.Attachment = require('./structures/Attachment');
|
||||
exports.AttachmentBuilder = require('./structures/AttachmentBuilder');
|
||||
exports.ModalBuilder = require('./structures/ModalBuilder');
|
||||
exports.MediaChannel = require('./structures/MediaChannel');
|
||||
exports.MediaGalleryComponent = require('./structures/MediaGalleryComponent');
|
||||
exports.MediaGalleryItem = require('./structures/MediaGalleryItem');
|
||||
exports.MessageCollector = require('./structures/MessageCollector');
|
||||
exports.MessageComponentInteraction = require('./structures/MessageComponentInteraction');
|
||||
exports.MessageContextMenuCommandInteraction = require('./structures/MessageContextMenuCommandInteraction');
|
||||
@@ -176,11 +181,13 @@ exports.PartialGroupDMChannel = require('./structures/PartialGroupDMChannel');
|
||||
exports.PermissionOverwrites = require('./structures/PermissionOverwrites');
|
||||
exports.Poll = require('./structures/Poll').Poll;
|
||||
exports.PollAnswer = require('./structures/PollAnswer').PollAnswer;
|
||||
exports.PrimaryEntryPointCommandInteraction = require('./structures/PrimaryEntryPointCommandInteraction');
|
||||
exports.Presence = require('./structures/Presence').Presence;
|
||||
exports.ReactionCollector = require('./structures/ReactionCollector');
|
||||
exports.ReactionEmoji = require('./structures/ReactionEmoji');
|
||||
exports.RichPresenceAssets = require('./structures/Presence').RichPresenceAssets;
|
||||
exports.Role = require('./structures/Role').Role;
|
||||
exports.SectionComponent = require('./structures/SectionComponent');
|
||||
exports.SelectMenuBuilder = require('./structures/SelectMenuBuilder');
|
||||
exports.ChannelSelectMenuBuilder = require('./structures/ChannelSelectMenuBuilder');
|
||||
exports.MentionableSelectMenuBuilder = require('./structures/MentionableSelectMenuBuilder');
|
||||
@@ -202,7 +209,9 @@ exports.RoleSelectMenuInteraction = require('./structures/RoleSelectMenuInteract
|
||||
exports.StringSelectMenuInteraction = require('./structures/StringSelectMenuInteraction');
|
||||
exports.UserSelectMenuInteraction = require('./structures/UserSelectMenuInteraction');
|
||||
exports.SelectMenuOptionBuilder = require('./structures/SelectMenuOptionBuilder');
|
||||
exports.SeparatorComponent = require('./structures/SeparatorComponent');
|
||||
exports.SKU = require('./structures/SKU').SKU;
|
||||
exports.SoundboardSound = require('./structures/SoundboardSound.js').SoundboardSound;
|
||||
exports.StringSelectMenuOptionBuilder = require('./structures/StringSelectMenuOptionBuilder');
|
||||
exports.StageChannel = require('./structures/StageChannel');
|
||||
exports.StageInstance = require('./structures/StageInstance').StageInstance;
|
||||
@@ -212,12 +221,15 @@ exports.StickerPack = require('./structures/StickerPack');
|
||||
exports.Team = require('./structures/Team');
|
||||
exports.TeamMember = require('./structures/TeamMember');
|
||||
exports.TextChannel = require('./structures/TextChannel');
|
||||
exports.TextDisplayComponent = require('./structures/TextDisplayComponent');
|
||||
exports.TextInputBuilder = require('./structures/TextInputBuilder');
|
||||
exports.TextInputComponent = require('./structures/TextInputComponent');
|
||||
exports.ThreadChannel = require('./structures/ThreadChannel');
|
||||
exports.ThreadMember = require('./structures/ThreadMember');
|
||||
exports.ThreadOnlyChannel = require('./structures/ThreadOnlyChannel');
|
||||
exports.ThumbnailComponent = require('./structures/ThumbnailComponent');
|
||||
exports.Typing = require('./structures/Typing');
|
||||
exports.UnfurledMediaItem = require('./structures/UnfurledMediaItem');
|
||||
exports.User = require('./structures/User');
|
||||
exports.UserContextMenuCommandInteraction = require('./structures/UserContextMenuCommandInteraction');
|
||||
exports.VoiceChannelEffect = require('./structures/VoiceChannelEffect');
|
||||
|
||||
@@ -261,6 +261,7 @@ class ApplicationCommandManager extends CachedManager {
|
||||
dm_permission: command.dmPermission ?? command.dm_permission,
|
||||
integration_types: command.integrationTypes ?? command.integration_types,
|
||||
contexts: command.contexts,
|
||||
handler: command.handler,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ class BaseGuildEmojiManager extends CachedManager {
|
||||
* @returns {?GuildEmoji}
|
||||
*/
|
||||
resolve(emoji) {
|
||||
if (emoji instanceof ReactionEmoji) return super.cache.get(emoji.id) ?? null;
|
||||
if (emoji instanceof ApplicationEmoji) return super.cache.get(emoji.id) ?? null;
|
||||
if (emoji instanceof ReactionEmoji) return this.cache.get(emoji.id) ?? null;
|
||||
if (emoji instanceof ApplicationEmoji) return this.cache.get(emoji.id) ?? null;
|
||||
return super.resolve(emoji);
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,13 @@ class ChannelManager extends CachedManager {
|
||||
|
||||
channel?.parent?.threads?.cache.delete(id);
|
||||
this.cache.delete(id);
|
||||
|
||||
if (channel?.threads) {
|
||||
for (const threadId of channel.threads.cache.keys()) {
|
||||
this.cache.delete(threadId);
|
||||
channel.guild?.channels.cache.delete(threadId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -97,14 +97,14 @@ class GuildBanManager extends CachedManager {
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
fetch(options) {
|
||||
async fetch(options) {
|
||||
if (!options) return this._fetchMany();
|
||||
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 && cache === undefined) {
|
||||
return Promise.reject(new DiscordjsError(ErrorCodes.FetchBanResolveId));
|
||||
throw new DiscordjsError(ErrorCodes.FetchBanResolveId);
|
||||
}
|
||||
|
||||
return this._fetchMany(options);
|
||||
|
||||
@@ -84,7 +84,7 @@ class GuildChannelManager extends CachedManager {
|
||||
* @returns {?(GuildChannel|ThreadChannel)}
|
||||
*/
|
||||
resolve(channel) {
|
||||
if (channel instanceof ThreadChannel) return super.cache.get(channel.id) ?? null;
|
||||
if (channel instanceof ThreadChannel) return this.cache.get(channel.id) ?? null;
|
||||
return super.resolve(channel);
|
||||
}
|
||||
|
||||
@@ -230,13 +230,13 @@ class GuildChannelManager extends CachedManager {
|
||||
async createWebhook({ channel, name, avatar, reason }) {
|
||||
const id = this.resolveId(channel);
|
||||
if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable');
|
||||
if (typeof avatar === 'string' && !avatar.startsWith('data:')) {
|
||||
avatar = await resolveImage(avatar);
|
||||
}
|
||||
|
||||
const resolvedImage = await resolveImage(avatar);
|
||||
|
||||
const data = await this.client.rest.post(Routes.channelWebhooks(id), {
|
||||
body: {
|
||||
name,
|
||||
avatar,
|
||||
avatar: resolvedImage,
|
||||
},
|
||||
reason,
|
||||
});
|
||||
|
||||
@@ -39,14 +39,14 @@ class GuildEmojiRoleManager extends DataManager {
|
||||
* @param {RoleResolvable|RoleResolvable[]|Collection<Snowflake, Role>} roleOrRoles The role or roles to add
|
||||
* @returns {Promise<GuildEmoji>}
|
||||
*/
|
||||
add(roleOrRoles) {
|
||||
async add(roleOrRoles) {
|
||||
if (!Array.isArray(roleOrRoles) && !(roleOrRoles instanceof Collection)) roleOrRoles = [roleOrRoles];
|
||||
|
||||
const resolvedRoles = [];
|
||||
for (const role of roleOrRoles.values()) {
|
||||
const resolvedRole = this.guild.roles.resolveId(role);
|
||||
if (!resolvedRole) {
|
||||
return Promise.reject(new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'roles', role));
|
||||
throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'roles', role);
|
||||
}
|
||||
resolvedRoles.push(resolvedRole);
|
||||
}
|
||||
@@ -60,14 +60,14 @@ class GuildEmojiRoleManager extends DataManager {
|
||||
* @param {RoleResolvable|RoleResolvable[]|Collection<Snowflake, Role>} roleOrRoles The role or roles to remove
|
||||
* @returns {Promise<GuildEmoji>}
|
||||
*/
|
||||
remove(roleOrRoles) {
|
||||
async remove(roleOrRoles) {
|
||||
if (!Array.isArray(roleOrRoles) && !(roleOrRoles instanceof Collection)) roleOrRoles = [roleOrRoles];
|
||||
|
||||
const resolvedRoleIds = [];
|
||||
for (const role of roleOrRoles.values()) {
|
||||
const roleId = this.guild.roles.resolveId(role);
|
||||
if (!roleId) {
|
||||
return Promise.reject(new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'roles', role));
|
||||
throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'roles', role);
|
||||
}
|
||||
resolvedRoleIds.push(roleId);
|
||||
}
|
||||
|
||||
@@ -121,22 +121,22 @@ class GuildInviteManager extends CachedManager {
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
fetch(options) {
|
||||
async fetch(options) {
|
||||
if (!options) return this._fetchMany();
|
||||
if (typeof options === 'string') {
|
||||
const code = resolveInviteCode(options);
|
||||
if (!code) return Promise.reject(new DiscordjsError(ErrorCodes.InviteResolveCode));
|
||||
if (!code) throw new DiscordjsError(ErrorCodes.InviteResolveCode);
|
||||
return this._fetchSingle({ code, cache: true });
|
||||
}
|
||||
if (!options.code) {
|
||||
if (options.channelId) {
|
||||
const id = this.guild.channels.resolveId(options.channelId);
|
||||
if (!id) return Promise.reject(new DiscordjsError(ErrorCodes.GuildChannelResolve));
|
||||
if (!id) throw new DiscordjsError(ErrorCodes.GuildChannelResolve);
|
||||
return this._fetchChannelMany(id, options.cache);
|
||||
}
|
||||
|
||||
if ('cache' in options) return this._fetchMany(options.cache);
|
||||
return Promise.reject(new DiscordjsError(ErrorCodes.InviteResolveCode));
|
||||
throw new DiscordjsError(ErrorCodes.InviteResolveCode);
|
||||
}
|
||||
return this._fetchSingle({
|
||||
...options,
|
||||
|
||||
@@ -4,8 +4,9 @@ const process = require('node:process');
|
||||
const { setTimeout, clearTimeout } = require('node:timers');
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const { makeURLSearchParams } = require('@discordjs/rest');
|
||||
const { Routes, RouteBases } = require('discord-api-types/v10');
|
||||
const { GatewayOpcodes, Routes, RouteBases } = require('discord-api-types/v10');
|
||||
const CachedManager = require('./CachedManager');
|
||||
const { ErrorCodes, DiscordjsError } = require('../errors/index.js');
|
||||
const ShardClientUtil = require('../sharding/ShardClientUtil');
|
||||
const { Guild } = require('../structures/Guild');
|
||||
const GuildChannel = require('../structures/GuildChannel');
|
||||
@@ -18,6 +19,7 @@ const { resolveImage } = require('../util/DataResolver');
|
||||
const Events = require('../util/Events');
|
||||
const PermissionsBitField = require('../util/PermissionsBitField');
|
||||
const SystemChannelFlagsBitField = require('../util/SystemChannelFlagsBitField');
|
||||
const { _transformAPIIncidentsData } = require('../util/Transformers.js');
|
||||
const { resolveColor } = require('../util/Util');
|
||||
|
||||
let cacheWarningEmitted = false;
|
||||
@@ -281,6 +283,112 @@ class GuildManager extends CachedManager {
|
||||
return data.reduce((coll, guild) => coll.set(guild.id, new OAuth2Guild(this.client, guild)), new Collection());
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} FetchSoundboardSoundsOptions
|
||||
* @param {Snowflake[]} guildIds The ids of the guilds to fetch soundboard sounds for
|
||||
* @param {number} [time=10_000] The timeout for receipt of the soundboard sounds
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fetches soundboard sounds for the specified guilds.
|
||||
* @param {FetchSoundboardSoundsOptions} options The options for fetching soundboard sounds
|
||||
* @returns {Promise<Collection<Snowflake, Collection<Snowflake, SoundboardSound>>>}
|
||||
* @example
|
||||
* // Fetch soundboard sounds for multiple guilds
|
||||
* const soundboardSounds = await client.guilds.fetchSoundboardSounds({
|
||||
* guildIds: ['123456789012345678', '987654321098765432'],
|
||||
* })
|
||||
*
|
||||
* console.log(soundboardSounds.get('123456789012345678'));
|
||||
*/
|
||||
async fetchSoundboardSounds({ guildIds, time = 10_000 }) {
|
||||
const shardCount = this.client.options.shardCount;
|
||||
const shardIds = new Map();
|
||||
|
||||
for (const guildId of guildIds) {
|
||||
const shardId = ShardClientUtil.shardIdForGuildId(guildId, shardCount);
|
||||
const group = shardIds.get(shardId);
|
||||
|
||||
if (group) group.push(guildId);
|
||||
else shardIds.set(shardId, [guildId]);
|
||||
}
|
||||
|
||||
for (const [shardId, shardGuildIds] of shardIds) {
|
||||
this.client.ws.shards.get(shardId).send({
|
||||
op: GatewayOpcodes.RequestSoundboardSounds,
|
||||
d: {
|
||||
guild_ids: shardGuildIds,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const remainingGuildIds = new Set(guildIds);
|
||||
|
||||
const fetchedSoundboardSounds = new Collection();
|
||||
|
||||
const handler = (soundboardSounds, guild) => {
|
||||
timeout.refresh();
|
||||
|
||||
if (!remainingGuildIds.has(guild.id)) return;
|
||||
|
||||
fetchedSoundboardSounds.set(guild.id, soundboardSounds);
|
||||
|
||||
remainingGuildIds.delete(guild.id);
|
||||
|
||||
if (remainingGuildIds.size === 0) {
|
||||
clearTimeout(timeout);
|
||||
this.client.removeListener(Events.SoundboardSounds, handler);
|
||||
this.client.decrementMaxListeners();
|
||||
|
||||
resolve(fetchedSoundboardSounds);
|
||||
}
|
||||
};
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
this.client.removeListener(Events.SoundboardSounds, handler);
|
||||
this.client.decrementMaxListeners();
|
||||
reject(new DiscordjsError(ErrorCodes.GuildSoundboardSoundsTimeout));
|
||||
}, time).unref();
|
||||
|
||||
this.client.incrementMaxListeners();
|
||||
this.client.on(Events.SoundboardSounds, handler);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Options used to set incident actions. Supplying `null` to any option will disable the action.
|
||||
* @typedef {Object} IncidentActionsEditOptions
|
||||
* @property {?DateResolvable} [invitesDisabledUntil] When invites should be enabled again
|
||||
* @property {?DateResolvable} [dmsDisabledUntil] When direct messages should be enabled again
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets the incident actions for a guild.
|
||||
* @param {GuildResolvable} guild The guild
|
||||
* @param {IncidentActionsEditOptions} incidentActions The incident actions to set
|
||||
* @returns {Promise<IncidentActions>}
|
||||
*/
|
||||
async setIncidentActions(guild, { invitesDisabledUntil, dmsDisabledUntil }) {
|
||||
const guildId = this.resolveId(guild);
|
||||
|
||||
const data = await this.client.rest.put(Routes.guildIncidentActions(guildId), {
|
||||
body: {
|
||||
invites_disabled_until: invitesDisabledUntil && new Date(invitesDisabledUntil).toISOString(),
|
||||
dms_disabled_until: dmsDisabledUntil && new Date(dmsDisabledUntil).toISOString(),
|
||||
},
|
||||
});
|
||||
|
||||
const parsedData = _transformAPIIncidentsData(data);
|
||||
const resolvedGuild = this.resolve(guild);
|
||||
|
||||
if (resolvedGuild) {
|
||||
resolvedGuild.incidentsData = parsedData;
|
||||
}
|
||||
|
||||
return parsedData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a URL for the PNG widget of a guild.
|
||||
* @param {GuildResolvable} guild The guild of the widget image
|
||||
|
||||
@@ -54,8 +54,8 @@ class GuildMemberManager extends CachedManager {
|
||||
resolve(member) {
|
||||
const memberResolvable = super.resolve(member);
|
||||
if (memberResolvable) return memberResolvable;
|
||||
const userResolvable = this.client.users.resolveId(member);
|
||||
if (userResolvable) return super.cache.get(userResolvable) ?? null;
|
||||
const userId = this.client.users.resolveId(member);
|
||||
if (userId) return this.cache.get(userId) ?? null;
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -67,8 +67,8 @@ class GuildMemberManager extends CachedManager {
|
||||
resolveId(member) {
|
||||
const memberResolvable = super.resolveId(member);
|
||||
if (memberResolvable) return memberResolvable;
|
||||
const userResolvable = this.client.users.resolveId(member);
|
||||
return this.cache.has(userResolvable) ? userResolvable : null;
|
||||
const userId = this.client.users.resolveId(member);
|
||||
return this.cache.has(userId) ? userId : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,7 +223,7 @@ class GuildMemberManager extends CachedManager {
|
||||
return this._add(data, cache);
|
||||
}
|
||||
|
||||
_fetchMany({
|
||||
async _fetchMany({
|
||||
limit = 0,
|
||||
withPresences: presences,
|
||||
users,
|
||||
@@ -231,7 +231,7 @@ class GuildMemberManager extends CachedManager {
|
||||
time = 120e3,
|
||||
nonce = DiscordSnowflake.generate().toString(),
|
||||
} = {}) {
|
||||
if (nonce.length > 32) return Promise.reject(new DiscordjsRangeError(ErrorCodes.MemberFetchNonceLength));
|
||||
if (nonce.length > 32) throw new DiscordjsRangeError(ErrorCodes.MemberFetchNonceLength);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!query && !users) query = '';
|
||||
@@ -461,7 +461,7 @@ class GuildMemberManager extends CachedManager {
|
||||
*/
|
||||
async kick(user, reason) {
|
||||
const id = this.client.users.resolveId(user);
|
||||
if (!id) return Promise.reject(new DiscordjsTypeError(ErrorCodes.InvalidType, 'user', 'UserResolvable'));
|
||||
if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'user', 'UserResolvable');
|
||||
|
||||
await this.client.rest.delete(Routes.guildMember(this.guild.id, id), { reason });
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ class GuildMemberRoleManager extends DataManager {
|
||||
* @readonly
|
||||
*/
|
||||
get color() {
|
||||
const coloredRoles = this.cache.filter(role => role.color);
|
||||
const coloredRoles = this.cache.filter(role => role.colors.primaryColor);
|
||||
if (!coloredRoles.size) return null;
|
||||
return coloredRoles.reduce((prev, role) => (role.comparePositionTo(prev) > 0 ? role : prev));
|
||||
}
|
||||
|
||||
@@ -41,15 +41,12 @@ class GuildScheduledEventManager extends CachedManager {
|
||||
* Options for setting a recurrence rule for a guild scheduled event.
|
||||
* @typedef {Object} GuildScheduledEventRecurrenceRuleOptions
|
||||
* @property {DateResolvable} startAt The time the recurrence rule interval starts at
|
||||
* @property {?DateResolvable} endAt The time the recurrence rule interval ends at
|
||||
* @property {GuildScheduledEventRecurrenceRuleFrequency} frequency How often the event occurs
|
||||
* @property {number} interval The spacing between the events
|
||||
* @property {?GuildScheduledEventRecurrenceRuleWeekday[]} byWeekday The days within a week to recur on
|
||||
* @property {?GuildScheduledEventRecurrenceRuleNWeekday[]} byNWeekday The days within a week to recur on
|
||||
* @property {?GuildScheduledEventRecurrenceRuleMonth[]} byMonth The months to recur on
|
||||
* @property {?number[]} byMonthDay The days within a month to recur on
|
||||
* @property {?number[]} byYearDay The days within a year to recur on
|
||||
* @property {?number} count The total amount of times the event is allowed to recur before stopping
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
214
packages/discord.js/src/managers/GuildSoundboardSoundManager.js
Normal file
214
packages/discord.js/src/managers/GuildSoundboardSoundManager.js
Normal file
@@ -0,0 +1,214 @@
|
||||
'use strict';
|
||||
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const { lazy } = require('@discordjs/util');
|
||||
const { Routes } = require('discord-api-types/v10');
|
||||
const CachedManager = require('./CachedManager.js');
|
||||
const { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');
|
||||
const { SoundboardSound } = require('../structures/SoundboardSound.js');
|
||||
const { resolveBase64, resolveFile } = require('../util/DataResolver.js');
|
||||
|
||||
const fileTypeMime = lazy(() => require('magic-bytes.js').filetypemime);
|
||||
|
||||
/**
|
||||
* Manages API methods for Soundboard Sounds and stores their cache.
|
||||
* @extends {CachedManager}
|
||||
*/
|
||||
class GuildSoundboardSoundManager extends CachedManager {
|
||||
constructor(guild, iterable) {
|
||||
super(guild.client, SoundboardSound, iterable);
|
||||
|
||||
/**
|
||||
* The guild this manager belongs to
|
||||
* @type {Guild}
|
||||
*/
|
||||
this.guild = guild;
|
||||
}
|
||||
|
||||
/**
|
||||
* The cache of Soundboard Sounds
|
||||
* @type {Collection<Snowflake, SoundboardSound>}
|
||||
* @name GuildSoundboardSoundManager#cache
|
||||
*/
|
||||
|
||||
_add(data, cache) {
|
||||
return super._add(data, cache, { extras: [this.guild], id: data.sound_id });
|
||||
}
|
||||
|
||||
/**
|
||||
* Data that resolves to give a SoundboardSound object. This can be:
|
||||
* * A SoundboardSound object
|
||||
* * A Snowflake
|
||||
* @typedef {SoundboardSound|Snowflake} SoundboardSoundResolvable
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resolves a SoundboardSoundResolvable to a SoundboardSound object.
|
||||
* @method resolve
|
||||
* @memberof GuildSoundboardSoundManager
|
||||
* @instance
|
||||
* @param {SoundboardSoundResolvable} soundboardSound The SoundboardSound resolvable to identify
|
||||
* @returns {?SoundboardSound}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resolves a {@link SoundboardSoundResolvable} to a {@link SoundboardSound} id.
|
||||
* @param {SoundboardSoundResolvable} soundboardSound The soundboard sound resolvable to resolve
|
||||
* @returns {?Snowflake}
|
||||
*/
|
||||
resolveId(soundboardSound) {
|
||||
if (soundboardSound instanceof this.holds) return soundboardSound.soundId;
|
||||
if (typeof soundboardSound === 'string') return soundboardSound;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options used to create a soundboard sound in a guild.
|
||||
* @typedef {Object} GuildSoundboardSoundCreateOptions
|
||||
* @property {BufferResolvable|Stream} file The file for the soundboard sound
|
||||
* @property {string} name The name for the soundboard sound
|
||||
* @property {string} [contentType] The content type for the soundboard sound file
|
||||
* @property {number} [volume] The volume (a double) for the soundboard sound, from 0 (inclusive) to 1. Defaults to 1
|
||||
* @property {Snowflake} [emojiId] The emoji id for the soundboard sound
|
||||
* @property {string} [emojiName] The emoji name for the soundboard sound
|
||||
* @property {string} [reason] The reason for creating the soundboard sound
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new guild soundboard sound.
|
||||
* @param {GuildSoundboardSoundCreateOptions} options Options for creating a guild soundboard sound
|
||||
* @returns {Promise<SoundboardSound>} The created soundboard sound
|
||||
* @example
|
||||
* // Create a new soundboard sound from a file on your computer
|
||||
* guild.soundboardSounds.create({ file: './sound.mp3', name: 'sound' })
|
||||
* .then(sound => console.log(`Created new soundboard sound with name ${sound.name}!`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async create({ contentType, emojiId, emojiName, file, name, reason, volume }) {
|
||||
const resolvedFile = await resolveFile(file);
|
||||
|
||||
const resolvedContentType = contentType ?? resolvedFile.contentType ?? fileTypeMime()(resolvedFile.data)[0];
|
||||
|
||||
const sound = resolveBase64(resolvedFile.data, resolvedContentType);
|
||||
|
||||
const body = { emoji_id: emojiId, emoji_name: emojiName, name, sound, volume };
|
||||
|
||||
const soundboardSound = await this.client.rest.post(Routes.guildSoundboardSounds(this.guild.id), {
|
||||
body,
|
||||
reason,
|
||||
});
|
||||
|
||||
return this._add(soundboardSound);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data for editing a soundboard sound.
|
||||
* @typedef {Object} GuildSoundboardSoundEditOptions
|
||||
* @property {string} [name] The name of the soundboard sound
|
||||
* @property {?number} [volume] The volume (a double) of the soundboard sound, from 0 (inclusive) to 1
|
||||
* @property {?Snowflake} [emojiId] The emoji id of the soundboard sound
|
||||
* @property {?string} [emojiName] The emoji name of the soundboard sound
|
||||
* @property {string} [reason] The reason for editing the soundboard sound
|
||||
*/
|
||||
|
||||
/**
|
||||
* Edits a soundboard sound.
|
||||
* @param {SoundboardSoundResolvable} soundboardSound The soundboard sound to edit
|
||||
* @param {GuildSoundboardSoundEditOptions} [options={}] The new data for the soundboard sound
|
||||
* @returns {Promise<SoundboardSound>}
|
||||
*/
|
||||
async edit(soundboardSound, options = {}) {
|
||||
const soundId = this.resolveId(soundboardSound);
|
||||
|
||||
if (!soundId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'soundboardSound', 'SoundboardSoundResolvable');
|
||||
|
||||
const { emojiId, emojiName, name, reason, volume } = options;
|
||||
|
||||
const body = { emoji_id: emojiId, emoji_name: emojiName, name, volume };
|
||||
|
||||
const data = await this.client.rest.patch(Routes.guildSoundboardSound(this.guild.id, soundId), {
|
||||
body,
|
||||
reason,
|
||||
});
|
||||
|
||||
const existing = this.cache.get(soundId);
|
||||
|
||||
if (existing) {
|
||||
const clone = existing._clone();
|
||||
|
||||
clone._patch(data);
|
||||
return clone;
|
||||
}
|
||||
|
||||
return this._add(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a soundboard sound.
|
||||
* @param {SoundboardSoundResolvable} soundboardSound The soundboard sound to delete
|
||||
* @param {string} [reason] Reason for deleting this soundboard sound
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async delete(soundboardSound, reason) {
|
||||
const soundId = this.resolveId(soundboardSound);
|
||||
|
||||
if (!soundId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'soundboardSound', 'SoundboardSoundResolvable');
|
||||
|
||||
await this.client.rest.delete(Routes.guildSoundboardSound(this.guild.id, soundId), { reason });
|
||||
}
|
||||
|
||||
/**
|
||||
* Options used to fetch a soundboard sound.
|
||||
* @typedef {BaseFetchOptions} FetchSoundboardSoundOptions
|
||||
* @property {SoundboardSoundResolvable} soundboardSound The soundboard sound to fetch
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options used to fetch soundboard sounds from Discord
|
||||
* @typedef {Object} FetchGuildSoundboardSoundsOptions
|
||||
* @property {boolean} [cache] Whether to cache the fetched soundboard sounds
|
||||
*/
|
||||
|
||||
/* eslint-disable max-len */
|
||||
/**
|
||||
* Obtains one or more soundboard sounds from Discord, or the soundboard sound cache if they're already available.
|
||||
* @param {SoundboardSoundResolvable|FetchSoundboardSoundOptions|FetchGuildSoundboardSoundsOptions} [options] Options for fetching soundboard sound(s)
|
||||
* @returns {Promise<SoundboardSound|Collection<Snowflake, SoundboardSound>>}
|
||||
* @example
|
||||
* // Fetch a single soundboard sound
|
||||
* guild.soundboardSounds.fetch('222078108977594368')
|
||||
* .then(sound => console.log(`The soundboard sound name is: ${sound.name}`))
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Fetch all soundboard sounds from the guild
|
||||
* guild.soundboardSounds.fetch()
|
||||
* .then(sounds => console.log(`There are ${sounds.size} soundboard sounds.`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
/* eslint-enable max-len */
|
||||
async fetch(options) {
|
||||
if (!options) return this._fetchMany();
|
||||
const { cache, force, soundboardSound } = options;
|
||||
const resolvedSoundboardSound = this.resolveId(soundboardSound ?? options);
|
||||
if (resolvedSoundboardSound) return this._fetchSingle({ cache, force, soundboardSound: resolvedSoundboardSound });
|
||||
return this._fetchMany({ cache });
|
||||
}
|
||||
|
||||
async _fetchSingle({ cache, force, soundboardSound } = {}) {
|
||||
if (!force) {
|
||||
const existing = this.cache.get(soundboardSound);
|
||||
if (existing) return existing;
|
||||
}
|
||||
|
||||
const data = await this.client.rest.get(Routes.guildSoundboardSound(this.guild.id, soundboardSound));
|
||||
return this._add(data, cache);
|
||||
}
|
||||
|
||||
async _fetchMany({ cache } = {}) {
|
||||
const data = await this.client.rest.get(Routes.guildSoundboardSounds(this.guild.id));
|
||||
|
||||
return data.items.reduce((coll, sound) => coll.set(sound.sound_id, this._add(sound, cache)), new Collection());
|
||||
}
|
||||
}
|
||||
|
||||
exports.GuildSoundboardSoundManager = GuildSoundboardSoundManager;
|
||||
@@ -1,5 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const process = require('node:process');
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const { makeURLSearchParams } = require('@discordjs/rest');
|
||||
const { Routes } = require('discord-api-types/v10');
|
||||
@@ -10,6 +11,8 @@ const MessagePayload = require('../structures/MessagePayload');
|
||||
const { MakeCacheOverrideSymbol } = require('../util/Symbols');
|
||||
const { resolvePartialEmoji } = require('../util/Util');
|
||||
|
||||
let deprecationEmittedForFetchPinned = false;
|
||||
|
||||
/**
|
||||
* Manages API methods for Messages and holds their cache.
|
||||
* @extends {CachedManager}
|
||||
@@ -116,19 +119,83 @@ class MessageManager extends CachedManager {
|
||||
return data.reduce((_data, message) => _data.set(message.id, this._add(message, options.cache)), new Collection());
|
||||
}
|
||||
|
||||
/**
|
||||
* Options used to fetch pinned messages.
|
||||
*
|
||||
* @typedef {Object} FetchPinnedMessagesOptions
|
||||
* @property {DateResolvable} [before] Consider only pinned messages before this time
|
||||
* @property {number} [limit] The maximum number of pinned messages to return
|
||||
* @property {boolean} [cache] Whether to cache the pinned messages
|
||||
*/
|
||||
|
||||
/**
|
||||
* Data returned from fetching pinned messages.
|
||||
*
|
||||
* @typedef {Object} FetchPinnedMessagesResponse
|
||||
* @property {MessagePin[]} items The pinned messages
|
||||
* @property {boolean} hasMore Whether there are additional pinned messages that require a subsequent call
|
||||
*/
|
||||
|
||||
/**
|
||||
* Pinned message data returned from fetching pinned messages.
|
||||
*
|
||||
* @typedef {Object} MessagePin
|
||||
* @property {Date} pinnedAt The time the message was pinned at
|
||||
* @property {number} pinnedTimestamp The timestamp the message was pinned at
|
||||
* @property {Message} message The pinned message
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fetches the pinned messages of this channel and returns a collection of them.
|
||||
* <info>The returned Collection does not contain any reaction data of the messages.
|
||||
* Those need to be fetched separately.</info>
|
||||
*
|
||||
* @param {FetchPinnedMessagesOptions} [options={}] Options for fetching pinned messages
|
||||
* @returns {Promise<FetchPinnedMessagesResponse>}
|
||||
* @example
|
||||
* // Get pinned messages
|
||||
* channel.messages.fetchPins()
|
||||
* .then(messages => console.log(`Received ${messages.items.length} messages`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async fetchPins(options = {}) {
|
||||
const data = await this.client.rest.get(Routes.channelMessagesPins(this.channel.id), {
|
||||
query: makeURLSearchParams({
|
||||
...options,
|
||||
before: options.before && new Date(options.before).toISOString(),
|
||||
}),
|
||||
});
|
||||
|
||||
return {
|
||||
items: data.items.map(item => ({
|
||||
pinnedTimestamp: Date.parse(item.pinned_at),
|
||||
get pinnedAt() {
|
||||
return new Date(this.pinnedTimestamp);
|
||||
},
|
||||
message: this._add(item.message, options.cache),
|
||||
})),
|
||||
hasMore: data.has_more,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the pinned messages of this channel and returns a collection of them.
|
||||
* <info>The returned Collection does not contain any reaction data of the messages.
|
||||
* Those need to be fetched separately.</info>
|
||||
* @param {boolean} [cache=true] Whether to cache the message(s)
|
||||
* @deprecated Use {@link MessageManager#fetchPins} instead.
|
||||
* @returns {Promise<Collection<Snowflake, Message>>}
|
||||
* @example
|
||||
* // Get pinned messages
|
||||
* channel.messages.fetchPinned()
|
||||
* .then(messages => console.log(`Received ${messages.size} messages`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async fetchPinned(cache = true) {
|
||||
if (!deprecationEmittedForFetchPinned) {
|
||||
process.emitWarning(
|
||||
'The MessageManager#fetchPinned() method is deprecated. Use MessageManager#fetchPins() instead.',
|
||||
'DeprecationWarning',
|
||||
);
|
||||
|
||||
deprecationEmittedForFetchPinned = true;
|
||||
}
|
||||
|
||||
const data = await this.client.rest.get(Routes.channelPins(this.channel.id));
|
||||
const messages = new Collection();
|
||||
for (const message of data) messages.set(message.id, this._add(message, cache));
|
||||
@@ -219,7 +286,7 @@ class MessageManager extends CachedManager {
|
||||
message = this.resolveId(message);
|
||||
if (!message) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable');
|
||||
|
||||
await this.client.rest.put(Routes.channelPin(this.channel.id, message), { reason });
|
||||
await this.client.rest.put(Routes.channelMessagesPin(this.channel.id, message), { reason });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -232,7 +299,7 @@ class MessageManager extends CachedManager {
|
||||
message = this.resolveId(message);
|
||||
if (!message) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable');
|
||||
|
||||
await this.client.rest.delete(Routes.channelPin(this.channel.id, message), { reason });
|
||||
await this.client.rest.delete(Routes.channelMessagesPin(this.channel.id, message), { reason });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -62,15 +62,13 @@ class PermissionOverwriteManager extends CachedManager {
|
||||
* },
|
||||
* ], 'Needed to change permissions');
|
||||
*/
|
||||
set(overwrites, reason) {
|
||||
async set(overwrites, reason) {
|
||||
if (!Array.isArray(overwrites) && !(overwrites instanceof Collection)) {
|
||||
return Promise.reject(
|
||||
new DiscordjsTypeError(
|
||||
ErrorCodes.InvalidType,
|
||||
'overwrites',
|
||||
'Array or Collection of Permission Overwrites',
|
||||
true,
|
||||
),
|
||||
throw new DiscordjsTypeError(
|
||||
ErrorCodes.InvalidType,
|
||||
'overwrites',
|
||||
'Array or Collection of Permission Overwrites',
|
||||
true,
|
||||
);
|
||||
}
|
||||
return this.channel.edit({ permissionOverwrites: overwrites, reason });
|
||||
|
||||
@@ -12,6 +12,8 @@ const PermissionsBitField = require('../util/PermissionsBitField');
|
||||
const { setPosition, resolveColor } = require('../util/Util');
|
||||
|
||||
let cacheWarningEmitted = false;
|
||||
let deprecationEmittedForCreate = false;
|
||||
let deprecationEmittedForEdit = false;
|
||||
|
||||
/**
|
||||
* Manages API methods for roles and stores their cache.
|
||||
@@ -58,7 +60,7 @@ class RoleManager extends CachedManager {
|
||||
* @example
|
||||
* // Fetch a single role
|
||||
* message.guild.roles.fetch('222078108977594368')
|
||||
* .then(role => console.log(`The role color is: ${role.color}`))
|
||||
* .then(role => console.log(`The role color is: ${role.colors.primaryColor}`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async fetch(id, { cache = true, force = false } = {}) {
|
||||
@@ -112,11 +114,24 @@ class RoleManager extends CachedManager {
|
||||
* @returns {?Snowflake}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} RoleColorsResolvable
|
||||
* @property {ColorResolvable} primaryColor The primary color of the role
|
||||
* @property {ColorResolvable} [secondaryColor] The secondary color of the role.
|
||||
* This will make the role a gradient between the other provided colors
|
||||
* @property {ColorResolvable} [tertiaryColor] The tertiary color of the role.
|
||||
* When sending `tertiaryColor` the API enforces the role color to be a holographic style
|
||||
* with values of `primaryColor = 11127295`, `secondaryColor = 16759788`, and `tertiaryColor = 16761760`.
|
||||
* These values are available as a constant: `Constants.HolographicStyle`
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options used to create a new role.
|
||||
* @typedef {Object} RoleCreateOptions
|
||||
* @property {string} [name] The name of the new role
|
||||
* @property {ColorResolvable} [color] The data to create the role with
|
||||
* <warn>This property is deprecated. Use `colors` instead.</warn>
|
||||
* @property {RoleColorsResolvable} [colors] The colors to create the role with
|
||||
* @property {boolean} [hoist] Whether or not the new role should be hoisted
|
||||
* @property {PermissionResolvable} [permissions] The permissions for the new role
|
||||
* @property {number} [position] The position of the new role
|
||||
@@ -142,15 +157,30 @@ class RoleManager extends CachedManager {
|
||||
* // Create a new role with data and a reason
|
||||
* guild.roles.create({
|
||||
* name: 'Super Cool Blue People',
|
||||
* color: Colors.Blue,
|
||||
* reason: 'we needed a role for Super Cool People',
|
||||
* colors: {
|
||||
* primaryColor: Colors.Blue,
|
||||
* },
|
||||
* })
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Create a role with holographic colors
|
||||
* guild.roles.create({
|
||||
* name: 'Holographic Role',
|
||||
* reason: 'Creating a role with holographic effect',
|
||||
* colors: {
|
||||
* primaryColor: Constants.HolographicStyle.Primary,
|
||||
* secondaryColor: Constants.HolographicStyle.Secondary,
|
||||
* tertiaryColor: Constants.HolographicStyle.Tertiary,
|
||||
* },
|
||||
* })
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async create(options = {}) {
|
||||
let { name, color, hoist, permissions, position, mentionable, reason, icon, unicodeEmoji } = options;
|
||||
color &&= resolveColor(color);
|
||||
let { permissions, icon } = options;
|
||||
const { name, color, hoist, position, mentionable, reason, unicodeEmoji } = options;
|
||||
if (permissions !== undefined) permissions = new PermissionsBitField(permissions);
|
||||
if (icon) {
|
||||
const guildEmojiURL = this.guild.emojis.resolve(icon)?.imageURL();
|
||||
@@ -158,10 +188,30 @@ class RoleManager extends CachedManager {
|
||||
if (typeof icon !== 'string') icon = undefined;
|
||||
}
|
||||
|
||||
let colors = options.colors && {
|
||||
primary_color: resolveColor(options.colors.primaryColor),
|
||||
secondary_color: options.colors.secondaryColor && resolveColor(options.colors.secondaryColor),
|
||||
tertiary_color: options.colors.tertiaryColor && resolveColor(options.colors.tertiaryColor),
|
||||
};
|
||||
|
||||
if (color !== undefined) {
|
||||
if (!deprecationEmittedForCreate) {
|
||||
process.emitWarning(`Passing "color" to RoleManager#create() is deprecated. Use "colors" instead.`);
|
||||
}
|
||||
|
||||
deprecationEmittedForCreate = true;
|
||||
|
||||
colors = {
|
||||
primary_color: resolveColor(color),
|
||||
secondary_color: null,
|
||||
tertiary_color: null,
|
||||
};
|
||||
}
|
||||
|
||||
const data = await this.client.rest.post(Routes.guildRoles(this.guild.id), {
|
||||
body: {
|
||||
name,
|
||||
color,
|
||||
colors,
|
||||
hoist,
|
||||
permissions,
|
||||
mentionable,
|
||||
@@ -210,9 +260,29 @@ class RoleManager extends CachedManager {
|
||||
if (typeof icon !== 'string') icon = undefined;
|
||||
}
|
||||
|
||||
let colors = options.colors && {
|
||||
primary_color: resolveColor(options.colors.primaryColor),
|
||||
secondary_color: options.colors.secondaryColor && resolveColor(options.colors.secondaryColor),
|
||||
tertiary_color: options.colors.tertiaryColor && resolveColor(options.colors.tertiaryColor),
|
||||
};
|
||||
|
||||
if (options.color !== undefined) {
|
||||
if (!deprecationEmittedForEdit) {
|
||||
process.emitWarning(`Passing "color" to RoleManager#edit() is deprecated. Use "colors" instead.`);
|
||||
}
|
||||
|
||||
deprecationEmittedForEdit = true;
|
||||
|
||||
colors = {
|
||||
primary_color: resolveColor(options.color),
|
||||
secondary_color: null,
|
||||
tertiary_color: null,
|
||||
};
|
||||
}
|
||||
|
||||
const body = {
|
||||
name: options.name,
|
||||
color: options.color === undefined ? undefined : resolveColor(options.color),
|
||||
colors,
|
||||
hoist: options.hoist,
|
||||
permissions: options.permissions === undefined ? undefined : new PermissionsBitField(options.permissions),
|
||||
mentionable: options.mentionable,
|
||||
|
||||
@@ -97,7 +97,7 @@ class ThreadManager extends CachedManager {
|
||||
* Data that can be resolved to a Date object. This can be:
|
||||
* * A Date object
|
||||
* * A number representing a timestamp
|
||||
* * An [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) string
|
||||
* * An {@link https://en.wikipedia.org/wiki/ISO_8601 ISO 8601} string
|
||||
* @typedef {Date|number|string} DateResolvable
|
||||
*/
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ class Shard extends EventEmitter {
|
||||
* before resolving (`-1` or `Infinity` for no wait)
|
||||
* @returns {Promise<ChildProcess>}
|
||||
*/
|
||||
spawn(timeout = 30_000) {
|
||||
async spawn(timeout = 30_000) {
|
||||
if (this.process) throw new DiscordjsError(ErrorCodes.ShardingProcessExists, this.id);
|
||||
if (this.worker) throw new DiscordjsError(ErrorCodes.ShardingWorkerExists, this.id);
|
||||
|
||||
@@ -161,7 +161,7 @@ class Shard extends EventEmitter {
|
||||
*/
|
||||
this.emit(ShardEvents.Spawn, child);
|
||||
|
||||
if (timeout === -1 || timeout === Infinity) return Promise.resolve(child);
|
||||
if (timeout === -1 || timeout === Infinity) return child;
|
||||
return new Promise((resolve, reject) => {
|
||||
const cleanup = () => {
|
||||
clearTimeout(spawnTimeoutTimer);
|
||||
@@ -260,10 +260,10 @@ class Shard extends EventEmitter {
|
||||
* .then(count => console.log(`${count} guilds in shard ${shard.id}`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
fetchClientValue(prop) {
|
||||
async fetchClientValue(prop) {
|
||||
// Shard is dead (maybe respawning), don't cache anything and error immediately
|
||||
if (!this.process && !this.worker) {
|
||||
return Promise.reject(new DiscordjsError(ErrorCodes.ShardingNoChildExists, this.id));
|
||||
throw new DiscordjsError(ErrorCodes.ShardingNoChildExists, this.id);
|
||||
}
|
||||
|
||||
// Cached promise from previous call
|
||||
@@ -302,13 +302,13 @@ class Shard extends EventEmitter {
|
||||
* @param {*} [context] The context for the eval
|
||||
* @returns {Promise<*>} Result of the script execution
|
||||
*/
|
||||
eval(script, context) {
|
||||
async eval(script, context) {
|
||||
// Stringify the script if it's a Function
|
||||
const _eval = typeof script === 'function' ? `(${script})(this, ${JSON.stringify(context)})` : script;
|
||||
|
||||
// Shard is dead (maybe respawning), don't cache anything and error immediately
|
||||
if (!this.process && !this.worker) {
|
||||
return Promise.reject(new DiscordjsError(ErrorCodes.ShardingNoChildExists, this.id));
|
||||
throw new DiscordjsError(ErrorCodes.ShardingNoChildExists, this.id);
|
||||
}
|
||||
|
||||
// Cached promise from previous call
|
||||
|
||||
@@ -225,7 +225,8 @@ class ShardClientUtil {
|
||||
* Emitted when the client encounters an error.
|
||||
* <warn>Errors thrown within this event do not have a catch handler, it is
|
||||
* recommended to not use async functions as `error` event handlers. See the
|
||||
* [Node.js docs](https://nodejs.org/api/events.html#capture-rejections-of-promises) for details.</warn>
|
||||
* {@link https://nodejs.org/api/events.html#capture-rejections-of-promises Node.js documentation}
|
||||
* for details.)</warn>
|
||||
* @event Client#error
|
||||
* @param {Error} error The error encountered
|
||||
*/
|
||||
|
||||
@@ -256,9 +256,9 @@ class ShardingManager extends EventEmitter {
|
||||
* @param {BroadcastEvalOptions} [options={}] The options for the broadcast
|
||||
* @returns {Promise<*|Array<*>>} Results of the script execution
|
||||
*/
|
||||
broadcastEval(script, options = {}) {
|
||||
async broadcastEval(script, options = {}) {
|
||||
if (typeof script !== 'function') {
|
||||
return Promise.reject(new DiscordjsTypeError(ErrorCodes.ShardingInvalidEvalBroadcast));
|
||||
throw new DiscordjsTypeError(ErrorCodes.ShardingInvalidEvalBroadcast);
|
||||
}
|
||||
return this._performOnShards('eval', [`(${script})(this, ${JSON.stringify(options.context)})`], options.shard);
|
||||
}
|
||||
@@ -285,16 +285,16 @@ class ShardingManager extends EventEmitter {
|
||||
* @returns {Promise<*|Array<*>>} Results of the method execution
|
||||
* @private
|
||||
*/
|
||||
_performOnShards(method, args, shard) {
|
||||
if (this.shards.size === 0) return Promise.reject(new DiscordjsError(ErrorCodes.ShardingNoShards));
|
||||
async _performOnShards(method, args, shard) {
|
||||
if (this.shards.size === 0) throw new DiscordjsError(ErrorCodes.ShardingNoShards);
|
||||
|
||||
if (typeof shard === 'number') {
|
||||
if (this.shards.has(shard)) return this.shards.get(shard)[method](...args);
|
||||
return Promise.reject(new DiscordjsError(ErrorCodes.ShardingShardNotFound, shard));
|
||||
throw new DiscordjsError(ErrorCodes.ShardingShardNotFound, shard);
|
||||
}
|
||||
|
||||
if (this.shards.size !== this.shardList.length) {
|
||||
return Promise.reject(new DiscordjsError(ErrorCodes.ShardingInProcess));
|
||||
throw new DiscordjsError(ErrorCodes.ShardingInProcess);
|
||||
}
|
||||
|
||||
const promises = [];
|
||||
|
||||
@@ -174,6 +174,18 @@ class ApplicationCommand extends Base {
|
||||
this.contexts ??= null;
|
||||
}
|
||||
|
||||
if ('handler' in data) {
|
||||
/**
|
||||
* Determines whether the interaction is handled by the app's interactions handler or by Discord.
|
||||
* <info>Only available for {@link ApplicationCommandType.PrimaryEntryPoint} commands on
|
||||
* applications with the {@link ApplicationFlags.Embedded} flag (i.e, those that have an Activity)</info>
|
||||
* @type {?EntryPointCommandHandlerType}
|
||||
*/
|
||||
this.handler = data.handler;
|
||||
} else {
|
||||
this.handler ??= null;
|
||||
}
|
||||
|
||||
if ('version' in data) {
|
||||
/**
|
||||
* Autoincrementing version identifier updated during substantial record changes
|
||||
@@ -216,15 +228,20 @@ class ApplicationCommand extends Base {
|
||||
* @property {string} name The name of the command, must be in all lowercase if type is
|
||||
* {@link ApplicationCommandType.ChatInput}
|
||||
* @property {Object<Locale, string>} [nameLocalizations] The localizations for the command name
|
||||
* @property {string} description The description of the command, if type is {@link ApplicationCommandType.ChatInput}
|
||||
* @property {string} description The description of the command,
|
||||
* if type is {@link ApplicationCommandType.ChatInput} or {@link ApplicationCommandType.PrimaryEntryPoint}
|
||||
* @property {boolean} [nsfw] Whether the command is age-restricted
|
||||
* @property {Object<Locale, string>} [descriptionLocalizations] The localizations for the command description,
|
||||
* if type is {@link ApplicationCommandType.ChatInput}
|
||||
* if type is {@link ApplicationCommandType.ChatInput} or {@link ApplicationCommandType.PrimaryEntryPoint}
|
||||
* @property {ApplicationCommandType} [type=ApplicationCommandType.ChatInput] The type of the command
|
||||
* @property {ApplicationCommandOptionData[]} [options] Options for the command
|
||||
* @property {?PermissionResolvable} [defaultMemberPermissions] The bitfield used to determine the default permissions
|
||||
* a member needs in order to run the command
|
||||
* @property {boolean} [dmPermission] Whether the command is enabled in DMs
|
||||
* @property {ApplicationIntegrationType[]} [integrationTypes] Installation contexts where the command is available
|
||||
* @property {InteractionContextType[]} [contexts] Interaction contexts where the command can be used
|
||||
* @property {EntryPointCommandHandlerType} [handler] Whether the interaction is handled by the app's
|
||||
* interactions handler or by Discord.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -295,7 +312,7 @@ class ApplicationCommand extends Base {
|
||||
* @returns {Promise<ApplicationCommand>}
|
||||
* @example
|
||||
* // Edit the name localizations of this command
|
||||
* command.setLocalizedNames({
|
||||
* command.setNameLocalizations({
|
||||
* 'en-GB': 'test',
|
||||
* 'pt-BR': 'teste',
|
||||
* })
|
||||
@@ -419,7 +436,8 @@ class ApplicationCommand extends Base {
|
||||
this.descriptionLocalizations ?? {},
|
||||
) ||
|
||||
!isEqual(command.integrationTypes ?? command.integration_types ?? [], this.integrationTypes ?? []) ||
|
||||
!isEqual(command.contexts ?? [], this.contexts ?? [])
|
||||
!isEqual(command.contexts ?? [], this.contexts ?? []) ||
|
||||
('handler' in command && command.handler !== this.handler)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -16,37 +16,42 @@ class ApplicationEmoji extends Emoji {
|
||||
*/
|
||||
this.application = application;
|
||||
|
||||
/**
|
||||
* The user who created this emoji
|
||||
* @type {?User}
|
||||
*/
|
||||
this.author = null;
|
||||
|
||||
this.managed = null;
|
||||
this.requiresColons = null;
|
||||
|
||||
this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
if ('name' in data) this.name = data.name;
|
||||
if (data.user) this.author = this.client.users._add(data.user);
|
||||
if (data.user) {
|
||||
/**
|
||||
* The user who created this emoji
|
||||
* @type {User}
|
||||
*/
|
||||
this.author = this.client.users._add(data.user);
|
||||
}
|
||||
|
||||
if ('managed' in data) {
|
||||
/**
|
||||
* Whether this emoji is managed by an external service
|
||||
* @type {?boolean}
|
||||
* Whether this emoji is managed by an external service. Always `false` for application emojis
|
||||
* @type {false}
|
||||
*/
|
||||
this.managed = data.managed;
|
||||
}
|
||||
|
||||
if ('require_colons' in data) {
|
||||
/**
|
||||
* Whether or not this emoji requires colons surrounding it
|
||||
* @type {?boolean}
|
||||
* Whether this emoji requires colons surrounding it. Always `true` for application emojis
|
||||
* @type {true}
|
||||
*/
|
||||
this.requiresColons = data.require_colons;
|
||||
}
|
||||
|
||||
if ('available' in data) {
|
||||
/**
|
||||
* Whether this emoji is available. Always `true` for application emojis
|
||||
* @type {true}
|
||||
*/
|
||||
this.available = data.available;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,7 +112,8 @@ class ApplicationEmoji extends Emoji {
|
||||
other.id === this.id &&
|
||||
other.name === this.name &&
|
||||
other.managed === this.managed &&
|
||||
other.requiresColons === this.requiresColons
|
||||
other.requiresColons === this.requiresColons &&
|
||||
other.available === this.available
|
||||
);
|
||||
}
|
||||
|
||||
@@ -115,4 +121,49 @@ class ApplicationEmoji extends Emoji {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The emoji's name
|
||||
* @name name
|
||||
* @memberof ApplicationEmoji
|
||||
* @instance
|
||||
* @type {string}
|
||||
* @readonly
|
||||
*/
|
||||
|
||||
/**
|
||||
* Whether the emoji is animated
|
||||
* @name animated
|
||||
* @memberof ApplicationEmoji
|
||||
* @instance
|
||||
* @type {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns a URL for the emoji.
|
||||
* @method imageURL
|
||||
* @memberof ApplicationEmoji
|
||||
* @instance
|
||||
* @param {EmojiURLOptions} [options] Options for the image URL
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
/**
|
||||
* The time the emoji was created at
|
||||
* @name createdAt
|
||||
* @memberof ApplicationEmoji
|
||||
* @instance
|
||||
* @type {Date}
|
||||
* @readonly
|
||||
*/
|
||||
|
||||
/**
|
||||
* The timestamp the emoji was created at
|
||||
* @name createdTimestamp
|
||||
* @memberof ApplicationEmoji
|
||||
* @instance
|
||||
* @type {number}
|
||||
* @readonly
|
||||
*/
|
||||
|
||||
module.exports = ApplicationEmoji;
|
||||
|
||||
@@ -58,7 +58,7 @@ class BaseGuildEmoji extends Emoji {
|
||||
* @method imageURL
|
||||
* @memberof BaseGuildEmoji
|
||||
* @instance
|
||||
* @param {BaseImageURLOptions} [options] Options for the image URL
|
||||
* @param {EmojiURLOptions} [options] Options for the emoji URL
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
@@ -72,4 +72,40 @@ class BaseGuildEmoji extends Emoji {
|
||||
* @deprecated Use {@link BaseGuildEmoji#imageURL} instead.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The emoji's name
|
||||
* @name name
|
||||
* @memberof BaseGuildEmoji
|
||||
* @instance
|
||||
* @type {string}
|
||||
* @readonly
|
||||
*/
|
||||
|
||||
/**
|
||||
* Whether or not the emoji is animated
|
||||
* @name animated
|
||||
* @memberof BaseGuildEmoji
|
||||
* @instance
|
||||
* @type {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
|
||||
/**
|
||||
* The time the emoji was created at.
|
||||
* @name createdAt
|
||||
* @memberof BaseGuildEmoji
|
||||
* @instance
|
||||
* @type {Date}
|
||||
* @readonly
|
||||
*/
|
||||
|
||||
/**
|
||||
* The timestamp the emoji was created at.
|
||||
* @name createdTimestamp
|
||||
* @memberof BaseGuildEmoji
|
||||
* @instance
|
||||
* @type {number}
|
||||
* @readonly
|
||||
*/
|
||||
|
||||
module.exports = BaseGuildEmoji;
|
||||
|
||||
@@ -122,6 +122,12 @@ class BaseInteraction extends Base {
|
||||
* @type {?InteractionContextType}
|
||||
*/
|
||||
this.context = data.context ?? null;
|
||||
|
||||
/**
|
||||
* Attachment size limit in bytes
|
||||
* @type {number}
|
||||
*/
|
||||
this.attachmentSizeLimit = data.attachment_size_limit;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,6 +225,16 @@ class BaseInteraction extends Base {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this interaction is a {@link PrimaryEntryPointCommandInteraction}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isPrimaryEntryPointCommand() {
|
||||
return (
|
||||
this.type === InteractionType.ApplicationCommand && this.commandType === ApplicationCommandType.PrimaryEntryPoint
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this interaction is a {@link MessageComponentInteraction}
|
||||
* @returns {boolean}
|
||||
|
||||
@@ -163,6 +163,17 @@ class ClientApplication extends Application {
|
||||
this.approximateUserInstallCount ??= null;
|
||||
}
|
||||
|
||||
if ('approximate_user_authorization_count' in data) {
|
||||
/**
|
||||
* An approximate amount of users that have OAuth2 authorizations for this application.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
this.approximateUserAuthorizationCount = data.approximate_user_authorization_count;
|
||||
} else {
|
||||
this.approximateUserAuthorizationCount ??= null;
|
||||
}
|
||||
|
||||
if ('guild_id' in data) {
|
||||
/**
|
||||
* The id of the guild associated with this application.
|
||||
@@ -173,26 +184,6 @@ class ClientApplication extends Application {
|
||||
this.guildId ??= null;
|
||||
}
|
||||
|
||||
if ('cover_image' in data) {
|
||||
/**
|
||||
* The hash of the application's cover image
|
||||
* @type {?string}
|
||||
*/
|
||||
this.cover = data.cover_image;
|
||||
} else {
|
||||
this.cover ??= null;
|
||||
}
|
||||
|
||||
if ('rpc_origins' in data) {
|
||||
/**
|
||||
* The application's RPC origins, if enabled
|
||||
* @type {string[]}
|
||||
*/
|
||||
this.rpcOrigins = data.rpc_origins;
|
||||
} else {
|
||||
this.rpcOrigins ??= [];
|
||||
}
|
||||
|
||||
if ('bot_require_code_grant' in data) {
|
||||
/**
|
||||
* If this application's bot requires a code grant when using the OAuth2 flow
|
||||
|
||||
@@ -64,8 +64,6 @@ class ClientUser extends User {
|
||||
},
|
||||
});
|
||||
|
||||
this.client.token = data.token;
|
||||
this.client.rest.setToken(data.token);
|
||||
const { updated } = this.client.actions.UserUpdate.handle(data);
|
||||
return updated ?? this;
|
||||
}
|
||||
|
||||
@@ -152,6 +152,7 @@ class CommandInteraction extends BaseInteraction {
|
||||
editReply() {}
|
||||
deleteReply() {}
|
||||
followUp() {}
|
||||
launchActivity() {}
|
||||
showModal() {}
|
||||
sendPremiumRequired() {}
|
||||
awaitModalSubmit() {}
|
||||
|
||||
@@ -14,6 +14,15 @@ class Component {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* The id of this component
|
||||
* @type {number}
|
||||
* @readonly
|
||||
*/
|
||||
get id() {
|
||||
return this.data.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of the component
|
||||
* @type {ComponentType}
|
||||
|
||||
60
packages/discord.js/src/structures/ContainerComponent.js
Normal file
60
packages/discord.js/src/structures/ContainerComponent.js
Normal file
@@ -0,0 +1,60 @@
|
||||
'use strict';
|
||||
|
||||
const Component = require('./Component');
|
||||
const { createComponent } = require('../util/Components');
|
||||
|
||||
/**
|
||||
* Represents a container component
|
||||
* @extends {Component}
|
||||
*/
|
||||
class ContainerComponent extends Component {
|
||||
constructor({ components, ...data }) {
|
||||
super(data);
|
||||
|
||||
/**
|
||||
* The components in this container
|
||||
* @type {Component[]}
|
||||
* @readonly
|
||||
*/
|
||||
this.components = components.map(component => createComponent(component));
|
||||
}
|
||||
|
||||
/**
|
||||
* The accent color of this container
|
||||
* @type {?number}
|
||||
* @readonly
|
||||
*/
|
||||
get accentColor() {
|
||||
return this.data.accent_color ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The hex accent color of this container
|
||||
* @type {?string}
|
||||
* @readonly
|
||||
*/
|
||||
get hexAccentColor() {
|
||||
return typeof this.data.accent_color === 'number'
|
||||
? `#${this.data.accent_color.toString(16).padStart(6, '0')}`
|
||||
: (this.data.accent_color ?? null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this container is spoilered
|
||||
* @type {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get spoiler() {
|
||||
return this.data.spoiler ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the API-compatible JSON for this component
|
||||
* @returns {APIContainerComponent}
|
||||
*/
|
||||
toJSON() {
|
||||
return { ...this.data, components: this.components.map(component => component.toJSON()) };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ContainerComponent;
|
||||
@@ -45,7 +45,7 @@ class Emoji extends Base {
|
||||
|
||||
/**
|
||||
* Returns a URL for the emoji or `null` if this is not a custom emoji.
|
||||
* @param {BaseImageURLOptions} [options] Options for the image URL
|
||||
* @param {EmojiURLOptions} [options] Options for the emoji URL
|
||||
* @returns {?string}
|
||||
*/
|
||||
imageURL(options) {
|
||||
|
||||
40
packages/discord.js/src/structures/FileComponent.js
Normal file
40
packages/discord.js/src/structures/FileComponent.js
Normal file
@@ -0,0 +1,40 @@
|
||||
'use strict';
|
||||
|
||||
const Component = require('./Component');
|
||||
const UnfurledMediaItem = require('./UnfurledMediaItem');
|
||||
|
||||
/**
|
||||
* Represents a file component
|
||||
* @extends {Component}
|
||||
*/
|
||||
class FileComponent extends Component {
|
||||
constructor({ file, ...data }) {
|
||||
super(data);
|
||||
|
||||
/**
|
||||
* The media associated with this file
|
||||
* @type {UnfurledMediaItem}
|
||||
* @readonly
|
||||
*/
|
||||
this.file = new UnfurledMediaItem(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this thumbnail is spoilered
|
||||
* @type {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get spoiler() {
|
||||
return this.data.spoiler ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the API-compatible JSON for this component
|
||||
* @returns {APIFileComponent}
|
||||
*/
|
||||
toJSON() {
|
||||
return { ...this.data, file: this.file.toJSON() };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = FileComponent;
|
||||
@@ -21,6 +21,7 @@ const GuildEmojiManager = require('../managers/GuildEmojiManager');
|
||||
const GuildInviteManager = require('../managers/GuildInviteManager');
|
||||
const GuildMemberManager = require('../managers/GuildMemberManager');
|
||||
const GuildScheduledEventManager = require('../managers/GuildScheduledEventManager');
|
||||
const { GuildSoundboardSoundManager } = require('../managers/GuildSoundboardSoundManager');
|
||||
const GuildStickerManager = require('../managers/GuildStickerManager');
|
||||
const PresenceManager = require('../managers/PresenceManager');
|
||||
const RoleManager = require('../managers/RoleManager');
|
||||
@@ -29,6 +30,7 @@ const VoiceStateManager = require('../managers/VoiceStateManager');
|
||||
const { resolveImage } = require('../util/DataResolver');
|
||||
const Status = require('../util/Status');
|
||||
const SystemChannelFlagsBitField = require('../util/SystemChannelFlagsBitField');
|
||||
const { _transformAPIIncidentsData } = require('../util/Transformers.js');
|
||||
const { discordSort, getSortableGroupTypes, resolvePartialEmoji } = require('../util/Util');
|
||||
|
||||
/**
|
||||
@@ -107,6 +109,12 @@ class Guild extends AnonymousGuild {
|
||||
*/
|
||||
this.autoModerationRules = new AutoModerationRuleManager(this);
|
||||
|
||||
/**
|
||||
* A manager of the soundboard sounds of this guild.
|
||||
* @type {GuildSoundboardSoundManager}
|
||||
*/
|
||||
this.soundboardSounds = new GuildSoundboardSoundManager(this);
|
||||
|
||||
if (!data) return;
|
||||
if (data.unavailable) {
|
||||
/**
|
||||
@@ -470,6 +478,34 @@ class Guild extends AnonymousGuild {
|
||||
stickers: data.stickers,
|
||||
});
|
||||
}
|
||||
|
||||
if ('incidents_data' in data) {
|
||||
/**
|
||||
* Incident actions of a guild.
|
||||
* @typedef {Object} IncidentActions
|
||||
* @property {?Date} invitesDisabledUntil When invites would be enabled again
|
||||
* @property {?Date} dmsDisabledUntil When direct messages would be enabled again
|
||||
* @property {?Date} dmSpamDetectedAt When direct message spam was detected
|
||||
* @property {?Date} raidDetectedAt When a raid was detected
|
||||
*/
|
||||
|
||||
/**
|
||||
* The incidents data of this guild.
|
||||
* <info>You will need to fetch the guild using {@link BaseGuild#fetch} if you want to receive
|
||||
* this property.</info>
|
||||
* @type {?IncidentActions}
|
||||
*/
|
||||
this.incidentsData = data.incidents_data && _transformAPIIncidentsData(data.incidents_data);
|
||||
} else {
|
||||
this.incidentsData ??= null;
|
||||
}
|
||||
|
||||
if (data.soundboard_sounds) {
|
||||
this.soundboardSounds.cache.clear();
|
||||
for (const soundboardSound of data.soundboard_sounds) {
|
||||
this.soundboardSounds._add(soundboardSound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1365,6 +1401,15 @@ class Guild extends AnonymousGuild {
|
||||
return this.edit({ features });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the incident actions for a guild.
|
||||
* @param {IncidentActionsEditOptions} incidentActions The incident actions to set
|
||||
* @returns {Promise<IncidentActions>}
|
||||
*/
|
||||
async setIncidentActions(incidentActions) {
|
||||
return this.client.guilds.setIncidentActions(this.id, incidentActions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this guild equals another guild. It compares all properties, so for most operations
|
||||
* it is advisable to just compare `guild.id === guild2.id` as it is much faster and is often
|
||||
|
||||
@@ -32,6 +32,7 @@ const Targets = {
|
||||
AutoModeration: 'AutoModeration',
|
||||
GuildOnboarding: 'GuildOnboarding',
|
||||
GuildOnboardingPrompt: 'GuildOnboardingPrompt',
|
||||
SoundboardSound: 'SoundboardSound',
|
||||
Unknown: 'Unknown',
|
||||
};
|
||||
|
||||
@@ -53,10 +54,11 @@ const Targets = {
|
||||
* * An application command
|
||||
* * An auto moderation rule
|
||||
* * A guild onboarding prompt
|
||||
* * A soundboard sound
|
||||
* * An object with an id key if target was deleted or fake entity
|
||||
* * An object where the keys represent either the new value or the old value
|
||||
* @typedef {?(Object|Guild|BaseChannel|User|Role|Invite|Webhook|GuildEmoji|Message|Integration|StageInstance|Sticker|
|
||||
* GuildScheduledEvent|ApplicationCommand|AutoModerationRule|GuildOnboardingPrompt)} AuditLogEntryTarget
|
||||
* GuildScheduledEvent|ApplicationCommand|AutoModerationRule|GuildOnboardingPrompt|SoundboardSound)} AuditLogEntryTarget
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -86,6 +88,8 @@ const Targets = {
|
||||
* * ApplicationCommandPermission
|
||||
* * GuildOnboarding
|
||||
* * GuildOnboardingPrompt
|
||||
* * SoundboardSound
|
||||
* * AutoModeration
|
||||
* * Unknown
|
||||
* @typedef {string} AuditLogTargetType
|
||||
*/
|
||||
@@ -199,7 +203,6 @@ class GuildAuditLogsEntry {
|
||||
|
||||
case AuditLogEvent.MemberMove:
|
||||
case AuditLogEvent.MessageDelete:
|
||||
case AuditLogEvent.MessageBulkDelete:
|
||||
this.extra = {
|
||||
channel: guild.channels.cache.get(data.options.channel_id) ?? { id: data.options.channel_id },
|
||||
count: Number(data.options.count),
|
||||
@@ -214,6 +217,7 @@ class GuildAuditLogsEntry {
|
||||
};
|
||||
break;
|
||||
|
||||
case AuditLogEvent.MessageBulkDelete:
|
||||
case AuditLogEvent.MemberDisconnect:
|
||||
this.extra = {
|
||||
count: Number(data.options.count),
|
||||
@@ -365,10 +369,14 @@ class GuildAuditLogsEntry {
|
||||
data.action_type === AuditLogEvent.OnboardingPromptCreate
|
||||
? new GuildOnboardingPrompt(guild.client, changesReduce(this.changes, { id: data.target_id }), guild.id)
|
||||
: changesReduce(this.changes, { id: data.target_id });
|
||||
} else if (targetType === Targets.GuildOnboarding) {
|
||||
this.target = changesReduce(this.changes, { id: data.target_id });
|
||||
} else if (targetType === Targets.Role) {
|
||||
this.target = guild.roles.cache.get(data.target_id) ?? { id: data.target_id };
|
||||
} else if (targetType === Targets.Emoji) {
|
||||
this.target = guild.emojis.cache.get(data.target_id) ?? { id: data.target_id };
|
||||
} else if (targetType === Targets.SoundboardSound) {
|
||||
this.target = guild.soundboardSounds.cache.get(data.target_id) ?? { id: data.target_id };
|
||||
} else if (data.target_id) {
|
||||
this.target = guild[`${targetType.toLowerCase()}s`]?.cache.get(data.target_id) ?? { id: data.target_id };
|
||||
this.target = { id: data.target_id };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,7 +400,9 @@ class GuildAuditLogsEntry {
|
||||
if (target < 110) return Targets.GuildScheduledEvent;
|
||||
if (target < 120) return Targets.Thread;
|
||||
if (target < 130) return Targets.ApplicationCommand;
|
||||
if (target >= 140 && target < 150) return Targets.AutoModeration;
|
||||
if (target < 140) return Targets.SoundboardSound;
|
||||
if (target < 143) return Targets.AutoModeration;
|
||||
if (target < 146) return Targets.User;
|
||||
if (target >= 163 && target <= 165) return Targets.GuildOnboardingPrompt;
|
||||
if (target >= 160 && target < 170) return Targets.GuildOnboarding;
|
||||
return Targets.Unknown;
|
||||
@@ -420,6 +430,7 @@ class GuildAuditLogsEntry {
|
||||
AuditLogEvent.StickerCreate,
|
||||
AuditLogEvent.GuildScheduledEventCreate,
|
||||
AuditLogEvent.ThreadCreate,
|
||||
AuditLogEvent.SoundboardSoundCreate,
|
||||
AuditLogEvent.AutoModerationRuleCreate,
|
||||
AuditLogEvent.AutoModerationBlockMessage,
|
||||
AuditLogEvent.OnboardingPromptCreate,
|
||||
@@ -449,6 +460,7 @@ class GuildAuditLogsEntry {
|
||||
AuditLogEvent.StickerDelete,
|
||||
AuditLogEvent.GuildScheduledEventDelete,
|
||||
AuditLogEvent.ThreadDelete,
|
||||
AuditLogEvent.SoundboardSoundDelete,
|
||||
AuditLogEvent.AutoModerationRuleDelete,
|
||||
AuditLogEvent.OnboardingPromptDelete,
|
||||
].includes(action)
|
||||
@@ -473,8 +485,12 @@ class GuildAuditLogsEntry {
|
||||
AuditLogEvent.StickerUpdate,
|
||||
AuditLogEvent.GuildScheduledEventUpdate,
|
||||
AuditLogEvent.ThreadUpdate,
|
||||
AuditLogEvent.SoundboardSoundUpdate,
|
||||
AuditLogEvent.ApplicationCommandPermissionUpdate,
|
||||
AuditLogEvent.AutoModerationRuleUpdate,
|
||||
AuditLogEvent.AutoModerationBlockMessage,
|
||||
AuditLogEvent.AutoModerationFlagToChannel,
|
||||
AuditLogEvent.AutoModerationUserCommunicationDisabled,
|
||||
AuditLogEvent.OnboardingPromptUpdate,
|
||||
AuditLogEvent.OnboardingUpdate,
|
||||
].includes(action)
|
||||
|
||||
@@ -265,8 +265,8 @@ class GuildChannel extends BaseChannel {
|
||||
* Locks in the permission overwrites from the parent channel.
|
||||
* @returns {Promise<GuildChannel>}
|
||||
*/
|
||||
lockPermissions() {
|
||||
if (!this.parent) return Promise.reject(new DiscordjsError(ErrorCodes.GuildChannelOrphan));
|
||||
async lockPermissions() {
|
||||
if (!this.parent) throw new DiscordjsError(ErrorCodes.GuildChannelOrphan);
|
||||
const permissionOverwrites = this.parent.permissionOverwrites.cache.map(overwrite => overwrite.toJSON());
|
||||
return this.edit({ permissionOverwrites });
|
||||
}
|
||||
|
||||
@@ -122,6 +122,20 @@ class GuildMember extends Base {
|
||||
} else {
|
||||
this.flags ??= new GuildMemberFlagsBitField().freeze();
|
||||
}
|
||||
|
||||
if (data.avatar_decoration_data) {
|
||||
/**
|
||||
* The member avatar decoration's data
|
||||
*
|
||||
* @type {?AvatarDecorationData}
|
||||
*/
|
||||
this.avatarDecorationData = {
|
||||
asset: data.avatar_decoration_data.asset,
|
||||
skuId: data.avatar_decoration_data.sku_id,
|
||||
};
|
||||
} else {
|
||||
this.avatarDecorationData = null;
|
||||
}
|
||||
}
|
||||
|
||||
_clone() {
|
||||
@@ -166,6 +180,15 @@ class GuildMember extends Base {
|
||||
return this.avatar && this.client.rest.cdn.guildMemberAvatar(this.guild.id, this.id, this.avatar, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* A link to the member's avatar decoration.
|
||||
*
|
||||
* @returns {?string}
|
||||
*/
|
||||
avatarDecorationURL() {
|
||||
return this.avatarDecorationData ? this.client.rest.cdn.avatarDecoration(this.avatarDecorationData.asset) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A link to the member's banner.
|
||||
* @param {ImageURLOptions} [options={}] Options for the banner URL
|
||||
@@ -195,6 +218,16 @@ class GuildMember extends Base {
|
||||
return this.bannerURL(options) ?? this.user.bannerURL(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* A link to the member's guild avatar decoration if they have one.
|
||||
* Otherwise, a link to their {@link User#avatarDecorationURL} will be returned.
|
||||
*
|
||||
* @returns {?string}
|
||||
*/
|
||||
displayAvatarDecorationURL() {
|
||||
return this.avatarDecorationURL() ?? this.user.avatarDecorationURL();
|
||||
}
|
||||
|
||||
/**
|
||||
* The time this member joined the guild
|
||||
* @type {?Date}
|
||||
@@ -237,7 +270,7 @@ class GuildMember extends Base {
|
||||
* @readonly
|
||||
*/
|
||||
get displayColor() {
|
||||
return this.roles.color?.color ?? 0;
|
||||
return this.roles.color?.colors.primaryColor ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -499,7 +532,10 @@ class GuildMember extends Base {
|
||||
this.communicationDisabledUntilTimestamp === member.communicationDisabledUntilTimestamp &&
|
||||
this.flags.bitfield === member.flags.bitfield &&
|
||||
(this._roles === member._roles ||
|
||||
(this._roles.length === member._roles.length && this._roles.every((role, i) => role === member._roles[i])))
|
||||
(this._roles.length === member._roles.length &&
|
||||
this._roles.every((role, index) => role === member._roles[index]))) &&
|
||||
this.avatarDecorationData?.asset === member.avatarDecorationData?.asset &&
|
||||
this.avatarDecorationData?.skuId === member.avatarDecorationData?.skuId
|
||||
);
|
||||
}
|
||||
|
||||
@@ -525,6 +561,7 @@ class GuildMember extends Base {
|
||||
json.bannerURL = this.bannerURL();
|
||||
json.displayAvatarURL = this.displayAvatarURL();
|
||||
json.displayBannerURL = this.displayBannerURL();
|
||||
json.avatarDecorationURL = this.avatarDecorationURL();
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
||||
31
packages/discord.js/src/structures/MediaGalleryComponent.js
Normal file
31
packages/discord.js/src/structures/MediaGalleryComponent.js
Normal file
@@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
const Component = require('./Component');
|
||||
const MediaGalleryItem = require('./MediaGalleryItem');
|
||||
|
||||
/**
|
||||
* Represents a media gallery component
|
||||
* @extends {Component}
|
||||
*/
|
||||
class MediaGalleryComponent extends Component {
|
||||
constructor({ items, ...data }) {
|
||||
super(data);
|
||||
|
||||
/**
|
||||
* The items in this media gallery
|
||||
* @type {MediaGalleryItem[]}
|
||||
* @readonly
|
||||
*/
|
||||
this.items = items.map(item => new MediaGalleryItem(item));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the API-compatible JSON for this component
|
||||
* @returns {APIMediaGalleryComponent}
|
||||
*/
|
||||
toJSON() {
|
||||
return { ...this.data, items: this.items.map(item => item.toJSON()) };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MediaGalleryComponent;
|
||||
51
packages/discord.js/src/structures/MediaGalleryItem.js
Normal file
51
packages/discord.js/src/structures/MediaGalleryItem.js
Normal file
@@ -0,0 +1,51 @@
|
||||
'use strict';
|
||||
|
||||
const UnfurledMediaItem = require('./UnfurledMediaItem');
|
||||
|
||||
/**
|
||||
* Represents an item in a media gallery
|
||||
*/
|
||||
class MediaGalleryItem {
|
||||
constructor({ media, ...data }) {
|
||||
/**
|
||||
* The API data associated with this component
|
||||
* @type {APIMediaGalleryItem}
|
||||
*/
|
||||
this.data = data;
|
||||
|
||||
/**
|
||||
* The media associated with this media gallery item
|
||||
* @type {UnfurledMediaItem}
|
||||
* @readonly
|
||||
*/
|
||||
this.media = new UnfurledMediaItem(media);
|
||||
}
|
||||
|
||||
/**
|
||||
* The description of this media gallery item
|
||||
* @type {?string}
|
||||
* @readonly
|
||||
*/
|
||||
get description() {
|
||||
return this.data.description ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this media gallery item is spoilered
|
||||
* @type {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get spoiler() {
|
||||
return this.data.spoiler ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the API-compatible JSON for this component
|
||||
* @returns {APIMediaGalleryItem}
|
||||
*/
|
||||
toJSON() {
|
||||
return { ...this.data, media: this.media.toJSON() };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MediaGalleryItem;
|
||||
@@ -9,6 +9,7 @@ const {
|
||||
MessageType,
|
||||
MessageFlags,
|
||||
PermissionFlagsBits,
|
||||
MessageReferenceType,
|
||||
} = require('discord-api-types/v10');
|
||||
const Attachment = require('./Attachment');
|
||||
const Base = require('./Base');
|
||||
@@ -22,7 +23,7 @@ const ReactionCollector = require('./ReactionCollector');
|
||||
const { Sticker } = require('./Sticker');
|
||||
const { DiscordjsError, ErrorCodes } = require('../errors');
|
||||
const ReactionManager = require('../managers/ReactionManager');
|
||||
const { createComponent } = require('../util/Components');
|
||||
const { createComponent, findComponentByCustomId } = require('../util/Components');
|
||||
const { NonSystemMessageTypes, MaxBulkDeletableMessageAge, UndeletableMessageTypes } = require('../util/Constants');
|
||||
const MessageFlagsBitField = require('../util/MessageFlagsBitField');
|
||||
const PermissionsBitField = require('../util/PermissionsBitField');
|
||||
@@ -150,10 +151,10 @@ class Message extends Base {
|
||||
|
||||
if ('components' in data) {
|
||||
/**
|
||||
* An array of action rows in the message.
|
||||
* An array of components in the message.
|
||||
* <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged intent
|
||||
* in a guild for messages that do not mention the client.</info>
|
||||
* @type {ActionRow[]}
|
||||
* @type {Component[]}
|
||||
*/
|
||||
this.components = data.components.map(component => createComponent(component));
|
||||
} else {
|
||||
@@ -452,7 +453,7 @@ class Message extends Base {
|
||||
|
||||
if (data.message_snapshots) {
|
||||
/**
|
||||
* The message associated with the message reference
|
||||
* The message snapshots associated with the message reference
|
||||
* @type {Collection<Snowflake, Message>}
|
||||
*/
|
||||
this.messageSnapshots = data.message_snapshots.reduce((coll, snapshot) => {
|
||||
@@ -590,7 +591,7 @@ class Message extends Base {
|
||||
*/
|
||||
get cleanContent() {
|
||||
// eslint-disable-next-line eqeqeq
|
||||
return this.content != null ? cleanContent(this.content, this.channel) : null;
|
||||
return this.content != null && this.channel ? cleanContent(this.content, this.channel) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -704,7 +705,11 @@ class Message extends Base {
|
||||
* @readonly
|
||||
*/
|
||||
get editable() {
|
||||
const precheck = Boolean(this.author.id === this.client.user.id && (!this.guild || this.channel?.viewable));
|
||||
const precheck = Boolean(
|
||||
this.author.id === this.client.user.id &&
|
||||
(!this.guild || this.channel?.viewable) &&
|
||||
this.reference?.type !== MessageReferenceType.Forward,
|
||||
);
|
||||
|
||||
// Regardless of permissions thread messages cannot be edited if
|
||||
// the thread is archived or the thread is locked and the bot does not have permission to manage threads.
|
||||
@@ -807,6 +812,7 @@ class Message extends Base {
|
||||
return Boolean(
|
||||
channel?.type === ChannelType.GuildAnnouncement &&
|
||||
!this.flags.has(MessageFlags.Crossposted) &&
|
||||
this.reference?.type !== MessageReferenceType.Forward &&
|
||||
this.type === MessageType.Default &&
|
||||
!this.poll &&
|
||||
channel.viewable &&
|
||||
@@ -824,8 +830,8 @@ class Message extends Base {
|
||||
* .then(msg => console.log(`Updated the content of a message to ${msg.content}`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
edit(options) {
|
||||
if (!this.channel) return Promise.reject(new DiscordjsError(ErrorCodes.ChannelNotCached));
|
||||
async edit(options) {
|
||||
if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached);
|
||||
return this.channel.messages.edit(this, options);
|
||||
}
|
||||
|
||||
@@ -840,8 +846,8 @@ class Message extends Base {
|
||||
* .catch(console.error);
|
||||
* }
|
||||
*/
|
||||
crosspost() {
|
||||
if (!this.channel) return Promise.reject(new DiscordjsError(ErrorCodes.ChannelNotCached));
|
||||
async crosspost() {
|
||||
if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached);
|
||||
return this.channel.messages.crosspost(this.id);
|
||||
}
|
||||
|
||||
@@ -939,8 +945,8 @@ class Message extends Base {
|
||||
* .then(() => console.log(`Replied to message "${message.content}"`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
reply(options) {
|
||||
if (!this.channel) return Promise.reject(new DiscordjsError(ErrorCodes.ChannelNotCached));
|
||||
async reply(options) {
|
||||
if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached);
|
||||
let data;
|
||||
|
||||
if (options instanceof MessagePayload) {
|
||||
@@ -956,6 +962,24 @@ class Message extends Base {
|
||||
return this.channel.send(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards this message
|
||||
*
|
||||
* @param {TextBasedChannelResolvable} channel The channel to forward this message to.
|
||||
* @returns {Promise<Message>}
|
||||
*/
|
||||
forward(channel) {
|
||||
const resolvedChannel = this.client.channels.resolve(channel);
|
||||
if (!resolvedChannel) throw new DiscordjsError(ErrorCodes.InvalidType, 'channel', 'TextBasedChannelResolvable');
|
||||
return resolvedChannel.send({
|
||||
forward: {
|
||||
message: this.id,
|
||||
channel: this.channelId,
|
||||
guild: this.guildId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for starting a thread on a message.
|
||||
* @typedef {Object} StartThreadOptions
|
||||
@@ -972,12 +996,12 @@ class Message extends Base {
|
||||
* @param {StartThreadOptions} [options] Options for starting a thread on this message
|
||||
* @returns {Promise<ThreadChannel>}
|
||||
*/
|
||||
startThread(options = {}) {
|
||||
if (!this.channel) return Promise.reject(new DiscordjsError(ErrorCodes.ChannelNotCached));
|
||||
async startThread(options = {}) {
|
||||
if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached);
|
||||
if (![ChannelType.GuildText, ChannelType.GuildAnnouncement].includes(this.channel.type)) {
|
||||
return Promise.reject(new DiscordjsError(ErrorCodes.MessageThreadParent));
|
||||
throw new DiscordjsError(ErrorCodes.MessageThreadParent);
|
||||
}
|
||||
if (this.hasThread) return Promise.reject(new DiscordjsError(ErrorCodes.MessageExistingThread));
|
||||
if (this.hasThread) throw new DiscordjsError(ErrorCodes.MessageExistingThread);
|
||||
return this.channel.threads.create({ ...options, startMessage: this });
|
||||
}
|
||||
|
||||
@@ -986,8 +1010,8 @@ class Message extends Base {
|
||||
* @param {boolean} [force=true] Whether to skip the cache check and request the API
|
||||
* @returns {Promise<Message>}
|
||||
*/
|
||||
fetch(force = true) {
|
||||
if (!this.channel) return Promise.reject(new DiscordjsError(ErrorCodes.ChannelNotCached));
|
||||
async fetch(force = true) {
|
||||
if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached);
|
||||
return this.channel.messages.fetch({ message: this.id, force });
|
||||
}
|
||||
|
||||
@@ -995,9 +1019,9 @@ class Message extends Base {
|
||||
* Fetches the webhook used to create this message.
|
||||
* @returns {Promise<?Webhook>}
|
||||
*/
|
||||
fetchWebhook() {
|
||||
if (!this.webhookId) return Promise.reject(new DiscordjsError(ErrorCodes.WebhookMessage));
|
||||
if (this.webhookId === this.applicationId) return Promise.reject(new DiscordjsError(ErrorCodes.WebhookApplication));
|
||||
async fetchWebhook() {
|
||||
if (!this.webhookId) throw new DiscordjsError(ErrorCodes.WebhookMessage);
|
||||
if (this.webhookId === this.applicationId) throw new DiscordjsError(ErrorCodes.WebhookApplication);
|
||||
return this.client.fetchWebhook(this.webhookId);
|
||||
}
|
||||
|
||||
@@ -1032,7 +1056,7 @@ class Message extends Base {
|
||||
* @returns {?MessageActionRowComponent}
|
||||
*/
|
||||
resolveComponent(customId) {
|
||||
return this.components.flatMap(row => row.components).find(component => component.customId === customId) ?? null;
|
||||
return findComponentByCustomId(this.components, customId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,7 @@ const { lazy } = require('@discordjs/util');
|
||||
const BaseInteraction = require('./BaseInteraction');
|
||||
const InteractionWebhook = require('./InteractionWebhook');
|
||||
const InteractionResponses = require('./interfaces/InteractionResponses');
|
||||
const { findComponentByCustomId } = require('../util/Components');
|
||||
|
||||
const getMessage = lazy(() => require('./Message').Message);
|
||||
|
||||
@@ -79,13 +80,11 @@ class MessageComponentInteraction extends BaseInteraction {
|
||||
|
||||
/**
|
||||
* The component which was interacted with
|
||||
* @type {MessageActionRowComponent|APIMessageActionRowComponent}
|
||||
* @type {MessageActionRowComponent|APIComponentInMessageActionRow}
|
||||
* @readonly
|
||||
*/
|
||||
get component() {
|
||||
return this.message.components
|
||||
.flatMap(row => row.components)
|
||||
.find(component => (component.customId ?? component.custom_id) === this.customId);
|
||||
return findComponentByCustomId(this.message.components, this.customId);
|
||||
}
|
||||
|
||||
// These are here only for documentation purposes - they are implemented by InteractionResponses
|
||||
@@ -98,6 +97,7 @@ class MessageComponentInteraction extends BaseInteraction {
|
||||
followUp() {}
|
||||
deferUpdate() {}
|
||||
update() {}
|
||||
launchActivity() {}
|
||||
showModal() {}
|
||||
sendPremiumRequired() {}
|
||||
awaitModalSubmit() {}
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
const { Buffer } = require('node:buffer');
|
||||
const { lazy, isJSONEncodable } = require('@discordjs/util');
|
||||
const { DiscordSnowflake } = require('@sapphire/snowflake');
|
||||
const { MessageFlags } = require('discord-api-types/v10');
|
||||
const ActionRowBuilder = require('./ActionRowBuilder');
|
||||
const { MessageFlags, MessageReferenceType } = require('discord-api-types/v10');
|
||||
const { DiscordjsError, DiscordjsRangeError, ErrorCodes } = require('../errors');
|
||||
const { resolveFile } = require('../util/DataResolver');
|
||||
const MessageFlagsBitField = require('../util/MessageFlagsBitField');
|
||||
@@ -149,7 +148,7 @@ class MessagePayload {
|
||||
}
|
||||
|
||||
const components = this.options.components?.map(component =>
|
||||
(isJSONEncodable(component) ? component : new ActionRowBuilder(component)).toJSON(),
|
||||
isJSONEncodable(component) ? component.toJSON() : this.target.client.options.jsonTransformer(component),
|
||||
);
|
||||
|
||||
let username;
|
||||
@@ -166,9 +165,7 @@ class MessagePayload {
|
||||
let flags;
|
||||
if (
|
||||
// eslint-disable-next-line eqeqeq
|
||||
this.options.flags != null ||
|
||||
(this.isMessage && this.options.reply === undefined) ||
|
||||
this.isMessageManager
|
||||
this.options.flags != null
|
||||
) {
|
||||
flags = new MessageFlagsBitField(this.options.flags).bitfield;
|
||||
}
|
||||
@@ -199,6 +196,22 @@ class MessagePayload {
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof this.options.forward === 'object') {
|
||||
const reference = this.options.forward.message;
|
||||
const channel_id = reference.channelId ?? this.target.client.channels.resolveId(this.options.forward.channel);
|
||||
const guild_id = reference.guildId ?? this.target.client.guilds.resolveId(this.options.forward.guild);
|
||||
const message_id = this.target.messages.resolveId(reference);
|
||||
if (message_id) {
|
||||
if (!channel_id) throw new DiscordjsError(ErrorCodes.InvalidType, 'channelId', 'TextBasedChannelResolvable');
|
||||
message_reference = {
|
||||
type: MessageReferenceType.Forward,
|
||||
message_id,
|
||||
channel_id,
|
||||
guild_id: guild_id ?? undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const attachments = this.options.files?.map((file, index) => ({
|
||||
id: index.toString(),
|
||||
description: file.description,
|
||||
@@ -235,7 +248,10 @@ class MessagePayload {
|
||||
components,
|
||||
username,
|
||||
avatar_url: avatarURL,
|
||||
allowed_mentions: content === undefined && message_reference === undefined ? undefined : allowedMentions,
|
||||
allowed_mentions:
|
||||
this.isMessage && message_reference === undefined && this.target.author.id !== this.target.client.user.id
|
||||
? undefined
|
||||
: allowedMentions,
|
||||
flags,
|
||||
message_reference,
|
||||
attachments: this.options.attachments,
|
||||
|
||||
@@ -119,6 +119,7 @@ class ModalSubmitInteraction extends BaseInteraction {
|
||||
deferUpdate() {}
|
||||
update() {}
|
||||
sendPremiumRequired() {}
|
||||
launchActivity() {}
|
||||
}
|
||||
|
||||
InteractionResponses.applyToClass(ModalSubmitInteraction, 'showModal');
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
const { BaseChannel } = require('./BaseChannel');
|
||||
const TextBasedChannel = require('./interfaces/TextBasedChannel');
|
||||
const { DiscordjsError, ErrorCodes } = require('../errors');
|
||||
const PartialGroupDMMessageManager = require('../managers/PartialGroupDMMessageManager');
|
||||
|
||||
/**
|
||||
* Represents a Partial Group DM Channel on Discord.
|
||||
* @extends {BaseChannel}
|
||||
* @implements {TextBasedChannel}
|
||||
*/
|
||||
class PartialGroupDMChannel extends BaseChannel {
|
||||
constructor(client, data) {
|
||||
@@ -25,7 +27,7 @@ class PartialGroupDMChannel extends BaseChannel {
|
||||
* The hash of the channel icon
|
||||
* @type {?string}
|
||||
*/
|
||||
this.icon = data.icon;
|
||||
this.icon = data.icon ?? null;
|
||||
|
||||
/**
|
||||
* Recipient data received in a {@link PartialGroupDMChannel}.
|
||||
@@ -37,13 +39,43 @@ class PartialGroupDMChannel extends BaseChannel {
|
||||
* The recipients of this Group DM Channel.
|
||||
* @type {PartialRecipient[]}
|
||||
*/
|
||||
this.recipients = data.recipients;
|
||||
this.recipients = data.recipients ?? [];
|
||||
|
||||
/**
|
||||
* A manager of the messages belonging to this channel
|
||||
* @type {PartialGroupDMMessageManager}
|
||||
*/
|
||||
this.messages = new PartialGroupDMMessageManager(this);
|
||||
|
||||
if ('owner_id' in data) {
|
||||
/**
|
||||
* The user id of the owner of this Group DM Channel
|
||||
* @type {?Snowflake}
|
||||
*/
|
||||
this.ownerId = data.owner_id;
|
||||
} else {
|
||||
this.ownerId ??= null;
|
||||
}
|
||||
|
||||
if ('last_message_id' in data) {
|
||||
/**
|
||||
* The channel's last message id, if one was sent
|
||||
* @type {?Snowflake}
|
||||
*/
|
||||
this.lastMessageId = data.last_message_id;
|
||||
} else {
|
||||
this.lastMessageId ??= null;
|
||||
}
|
||||
|
||||
if ('last_pin_timestamp' in data) {
|
||||
/**
|
||||
* The timestamp when the last pinned message was pinned, if there was one
|
||||
* @type {?number}
|
||||
*/
|
||||
this.lastPinTimestamp = data.last_pin_timestamp ? Date.parse(data.last_pin_timestamp) : null;
|
||||
} else {
|
||||
this.lastPinTimestamp ??= null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,13 +87,45 @@ class PartialGroupDMChannel extends BaseChannel {
|
||||
return this.icon && this.client.rest.cdn.channelIcon(this.id, this.icon, options);
|
||||
}
|
||||
|
||||
delete() {
|
||||
return Promise.reject(new DiscordjsError(ErrorCodes.DeleteGroupDMChannel));
|
||||
/**
|
||||
* Fetches the owner of this Group DM Channel.
|
||||
* @param {BaseFetchOptions} [options] The options for fetching the user
|
||||
* @returns {Promise<User>}
|
||||
*/
|
||||
async fetchOwner(options) {
|
||||
if (!this.ownerId) {
|
||||
throw new DiscordjsError(ErrorCodes.FetchOwnerId, 'group DM');
|
||||
}
|
||||
|
||||
return this.client.users.fetch(this.ownerId, options);
|
||||
}
|
||||
|
||||
fetch() {
|
||||
return Promise.reject(new DiscordjsError(ErrorCodes.FetchGroupDMChannel));
|
||||
async delete() {
|
||||
throw new DiscordjsError(ErrorCodes.DeleteGroupDMChannel);
|
||||
}
|
||||
|
||||
async fetch() {
|
||||
throw new DiscordjsError(ErrorCodes.FetchGroupDMChannel);
|
||||
}
|
||||
|
||||
// These are here only for documentation purposes - they are implemented by TextBasedChannel
|
||||
/* eslint-disable no-empty-function */
|
||||
get lastMessage() {}
|
||||
get lastPinAt() {}
|
||||
createMessageComponentCollector() {}
|
||||
awaitMessageComponent() {}
|
||||
}
|
||||
|
||||
TextBasedChannel.applyToClass(PartialGroupDMChannel, true, [
|
||||
'bulkDelete',
|
||||
'send',
|
||||
'sendTyping',
|
||||
'createMessageCollector',
|
||||
'awaitMessages',
|
||||
'fetchWebhooks',
|
||||
'createWebhook',
|
||||
'setRateLimitPerUser',
|
||||
'setNSFW',
|
||||
]);
|
||||
|
||||
module.exports = PartialGroupDMChannel;
|
||||
|
||||
@@ -180,8 +180,11 @@ class PermissionOverwrites extends Base {
|
||||
};
|
||||
}
|
||||
|
||||
const userOrRole = guild.roles.cache.get(overwrite.id) ?? guild.client.users.cache.get(overwrite.id);
|
||||
if (!userOrRole) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'parameter', 'User nor a Role');
|
||||
const userOrRole = guild.roles.resolve(overwrite.id) ?? guild.client.users.resolve(overwrite.id);
|
||||
if (!userOrRole) {
|
||||
throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'parameter', 'cached User or Role');
|
||||
}
|
||||
|
||||
const type = userOrRole instanceof Role ? OverwriteType.Role : OverwriteType.Member;
|
||||
|
||||
return {
|
||||
|
||||
@@ -97,9 +97,9 @@ class Poll extends Base {
|
||||
* Ends this poll.
|
||||
* @returns {Promise<Message>}
|
||||
*/
|
||||
end() {
|
||||
async end() {
|
||||
if (Date.now() > this.expiresTimestamp) {
|
||||
return Promise.reject(new DiscordjsError(ErrorCodes.PollAlreadyExpired));
|
||||
throw new DiscordjsError(ErrorCodes.PollAlreadyExpired);
|
||||
}
|
||||
|
||||
return this.message.channel.messages.endPoll(this.message.id);
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
const CommandInteraction = require('./CommandInteraction.js');
|
||||
|
||||
/**
|
||||
* Represents a primary entry point command interaction.
|
||||
* @extends {CommandInteraction}
|
||||
*/
|
||||
class PrimaryEntryPointCommandInteraction extends CommandInteraction {}
|
||||
|
||||
module.exports = PrimaryEntryPointCommandInteraction;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user