Compare commits

..

4 Commits

Author SHA1 Message Date
Vlad Frangu
d6c7b8fe05 chore(builders): release @discordjs/builders@1.10.0 2025-01-01 23:24:11 +02:00
Vlad Frangu
e9d6046047 chore(formatters): release @discordjs/formatters@0.6.0 2025-01-01 23:23:37 +02:00
Jiralite
24e20d27a9 build: bump discord-api-types to 0.37.114 2024-12-24 12:07:58 +00:00
Jiralite
8760fde9ff build: bump discord-api-types to 0.37.113 2024-12-22 21:58:29 +00:00
216 changed files with 1454 additions and 9862 deletions

2
.github/CODEOWNERS vendored
View File

@@ -1,5 +1,5 @@
# Learn how to add code owners here:
# https://help.github.com/articles/about-code-owners
# https://help.github.com/en/articles/about-code-owners
* @iCrawl

View File

@@ -1,4 +1,4 @@
# https://docs.github.com/actions/using-workflows/caching-dependencies-to-speed-up-workflows#force-deleting-cache-entries
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#force-deleting-cache-entries
name: Cleanup caches
on:
pull_request:

View File

@@ -103,15 +103,7 @@ 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 }}
@@ -121,15 +113,7 @@ 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 }}
@@ -139,10 +123,6 @@ 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 }}
@@ -152,10 +132,6 @@ 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 }}
@@ -179,50 +155,26 @@ 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

View File

@@ -9,9 +9,7 @@
<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://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>
<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>

View File

@@ -18,9 +18,8 @@ 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 || isExternal;
const isAny = isDeprecated || isProtected || isStatic || isAbstract || isReadonly || isOptional;
return isAny ? (
<div className="mb-1 flex gap-3">
@@ -34,7 +33,6 @@ 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;
}

View File

@@ -29,7 +29,6 @@ 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">

View File

@@ -51,13 +51,7 @@ export async function PropertyNode({
<LinkIcon aria-hidden size={16} />
</Link>
{property.displayName}
{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}`,
'',
)}`
: ''}
{property.isOptional ? '?' : ''} : <ExcerptNode node={property.typeExcerpt} version={version} />
</span>
</h3>

View File

@@ -20,7 +20,7 @@ export async function fetchDependencies({
return Object.entries<string>(parsedDependencies)
.filter(([key]) => key.startsWith('@discordjs/') && !key.includes('api-extractor'))
.map(([key, value]) => `${key.replace('@discordjs/', '').replaceAll('.', '-')}-${sanitizeVersion(value)}`);
.map(([key, value]) => `${key.replace('@discordjs/', '').replaceAll('.', '-')}-${value.replaceAll('.', '-')}`);
} catch {
return [];
}
@@ -36,12 +36,8 @@ export async function fetchDependencies({
return Object.entries<string>(parsedDependencies)
.filter(([key]) => key.startsWith('@discordjs/') && !key.includes('api-extractor'))
.map(([key, value]) => `${key.replace('@discordjs/', '').replaceAll('.', '-')}-${sanitizeVersion(value)}`);
.map(([key, value]) => `${key.replace('@discordjs/', '').replaceAll('.', '-')}-${value.replaceAll('.', '-')}`);
} catch {
return [];
}
}
function sanitizeVersion(version: string) {
return version.replaceAll('.', '-').replace(/^[\^~]/, '');
}

View File

@@ -6,19 +6,19 @@
"private": true,
"scripts": {
"build": "turbo run build --concurrency=4",
"build:affected": "turbo run build --filter=...[origin/v14] --concurrency=4",
"build:affected": "turbo run build --filter=...[origin/main] --concurrency=4",
"build:apps": "turbo run build:local --filter=...{apps/*} --concurrency=4",
"build:apps:affected": "turbo run build:local --filter=...{apps/*}[origin/v14] --concurrency=4",
"build:apps:affected": "turbo run build:local --filter=...{apps/*}[origin/main] --concurrency=4",
"test": "turbo run test --concurrency=4",
"test:affected": "turbo run test --filter=...[origin/v14] --concurrency=4",
"test:affected": "turbo run test --filter=...[origin/main] --concurrency=4",
"lint": "turbo run lint --concurrency=4",
"lint:affected": "turbo run lint --filter=...[origin/v14] --concurrency=4",
"lint:affected": "turbo run lint --filter=...[origin/main] --concurrency=4",
"format": "turbo run format --concurrency=4",
"format:affected": "turbo run format --filter=...[origin/v14] --concurrency=4",
"format:affected": "turbo run format --filter=...[origin/main] --concurrency=4",
"fmt": "turbo run format --concurrency=4",
"fmt:affected": "turbo run format --filter=...[origin/v14] --concurrency=4",
"fmt:affected": "turbo run format --filter=...[origin/main] --concurrency=4",
"docs": "turbo run docs --concurrency=4",
"docs:affected": "turbo run docs --filter=...[origin/v14] --concurrency=4",
"docs:affected": "turbo run docs --filter=...[origin/main] --concurrency=4",
"prepare": "is-ci || husky",
"update": "pnpm --recursive update --interactive",
"update:latest": "pnpm --recursive update --interactive --latest",

View File

@@ -41,32 +41,28 @@
"homepage": "https://discord.js.org",
"funding": "https://github.com/discordjs/discord.js?sponsor",
"dependencies": {
"@actions/core": "^1.11.1",
"@actions/core": "^1.10.1",
"@actions/glob": "^0.5.0",
"@aws-sdk/client-s3": "^3.787.0",
"@discordjs/scripts": "workspace:^",
"@vercel/blob": "^0.27.3",
"@vercel/blob": "^0.23.4",
"@vercel/postgres": "^0.9.0",
"cloudflare": "^4.2.0",
"meilisearch": "^0.38.0",
"p-limit": "^6.2.0",
"p-queue": "^8.1.0",
"tslib": "^2.8.1",
"undici": "7.8.0"
"p-limit": "^6.1.0",
"tslib": "^2.6.3",
"undici": "6.19.8"
},
"devDependencies": {
"@types/node": "^22.14.0",
"@vitest/coverage-v8": "^3.1.1",
"@types/node": "^18.19.45",
"@vitest/coverage-v8": "^2.0.5",
"cross-env": "^7.0.3",
"eslint": "^8.57.0",
"eslint-config-neon": "^0.1.62",
"eslint-formatter-pretty": "^6.0.1",
"prettier": "^3.5.3",
"terser": "^5.37.0",
"tsup": "^8.4.0",
"turbo": "^2.5.0",
"typescript": "~5.8.3",
"vitest": "^3.1.1"
"prettier": "^3.3.3",
"tsup": "^8.2.4",
"turbo": "^2.0.14",
"typescript": "~5.5.4",
"vitest": "^2.0.5"
},
"engines": {
"node": ">=18"

View File

@@ -9,7 +9,7 @@ runs:
with:
swap-size-gb: 10
- uses: pnpm/action-setup@v4.1.0
- uses: pnpm/action-setup@v4.0.0
name: Install pnpm
with:
run_install: false

View File

@@ -1,26 +1,13 @@
/* 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 ||
!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');
if (!process.env.DATABASE_URL) {
setFailed('DATABASE_URL is not set');
}
const pkg = getInput('package') || '*';
@@ -30,21 +17,6 @@ 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 = [];
@@ -54,14 +26,12 @@ 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 key = `${name.replace('@discordjs/', '')}/${version}.json`;
const { url } = await put(key, data, {
const { url } = await put(`${name.replace('@discordjs/', '')}/${version}.json`, data, {
access: 'public',
addRandomSuffix: false,
});
@@ -69,19 +39,6 @@ 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) {

View File

@@ -1,82 +1,32 @@
/* eslint-disable @typescript-eslint/no-loop-func */
import { readFile } from 'node:fs/promises';
import { basename, dirname, relative, sep } from 'node:path';
import process from 'node:process';
import { setTimeout as sleep } from 'node:timers/promises';
import { setFailed, getInput } from '@actions/core';
import { cwd } from 'node:process';
import { getInput } from '@actions/core';
import { create } from '@actions/glob';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { put } from '@vercel/blob';
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');
}
import pLimit from 'p-limit';
const pkg = getInput('package') || '*';
const version = getInput('version') || 'main';
const queue = new PQueue({ concurrency: 10, interval: 60_000, intervalCap: 1_000 });
const limit = pLimit(10);
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(process.cwd(), file)).split(sep)[1];
const pkgName = dirname(relative(cwd(), file)).split(sep)[1];
try {
promises.push(
queue.add(async () => {
// eslint-disable-next-line @typescript-eslint/no-loop-func
limit(async () => {
console.log(`Uploading ${file} with ${version} from ${pkgName}...`);
const name = basename(file).replace('main.', '');
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();
await put(`rewrite/${pkgName}/${version}.${name}`, data, {
access: 'public',
addRandomSuffix: false,
});
}),
);
} catch (error) {
@@ -86,9 +36,6 @@ 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);
}

View File

@@ -1,10 +0,0 @@
{
"$schema": "https://json.schemastore.org/tsconfig.json",
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": true,
"skipLibCheck": true
},
"include": ["__tests__/**/*.ts"],
"exclude": ["node_modules"]
}

View File

@@ -14,7 +14,6 @@ import type { IExcerptTokenRange } from './Excerpt.js';
* @public
*/
export interface IApiParameterOptions {
defaultValue: string | undefined;
isOptional: boolean;
isRest: boolean;
parameterName: string;
@@ -125,7 +124,6 @@ export function ApiParameterListMixin<TBaseClass extends IApiItemConstructor>(
isOptional: Boolean(parameterOptions.isOptional),
isRest: Boolean(parameterOptions.isRest),
parent: this,
defaultValue: parameterOptions.defaultValue,
});
this[_parameters].push(parameter);
@@ -173,7 +171,6 @@ export function ApiParameterListMixin<TBaseClass extends IApiItemConstructor>(
parameterTypeTokenRange: parameter.parameterTypeExcerpt.tokenRange,
isOptional: parameter.isOptional,
isRest: parameter.isRest,
defaultValue: parameter.defaultValue,
});
}

View File

@@ -41,7 +41,6 @@ const MinifyJSONMapping = {
constraintTokenRange: 'ctr',
dependencies: 'dp',
defaultTypeTokenRange: 'dtr',
defaultValue: 'dv',
docComment: 'd',
endIndex: 'en',
excerptTokens: 'ex',

View File

@@ -262,7 +262,6 @@ 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,
};
}

View File

@@ -12,7 +12,6 @@ import type { Excerpt } from '../mixins/Excerpt.js';
* @public
*/
export interface IParameterOptions {
defaultValue: string | undefined;
isOptional: boolean;
isRest: boolean;
name: string;
@@ -57,11 +56,6 @@ 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) {
@@ -70,7 +64,6 @@ export class Parameter {
this.isOptional = options.isOptional;
this.isRest = options.isRest;
this._parent = options.parent;
this.defaultValue = options.defaultValue;
}
/**

View File

@@ -114,7 +114,7 @@ interface DocgenEventJson {
}
interface DocgenParamJson {
default?: boolean | number | string;
default?: string;
description: string;
name: string;
nullable?: boolean;
@@ -155,7 +155,7 @@ interface DocgenMethodJson {
interface DocgenPropertyJson {
abstract?: boolean;
access?: DocgenAccess;
default?: boolean | number | string;
default?: string;
deprecated?: DocgenDeprecated;
description: string;
meta: DocgenMetaJson;
@@ -843,7 +843,6 @@ export class ApiModelGenerator {
const parameters: IApiParameterOptions[] = this._captureParameters(
nodesToCapture,
functionDeclaration.parameters,
jsDoc?.params,
);
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
@@ -1044,7 +1043,6 @@ export class ApiModelGenerator {
const parameters: IApiParameterOptions[] = this._captureParameters(
nodesToCapture,
methodDeclaration.parameters,
jsDoc?.params,
);
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
@@ -1139,11 +1137,7 @@ export class ApiModelGenerator {
methodSignature.typeParameters,
);
const parameters: IApiParameterOptions[] = this._captureParameters(
nodesToCapture,
methodSignature.parameters,
jsDoc?.params,
);
const parameters: IApiParameterOptions[] = this._captureParameters(nodesToCapture, methodSignature.parameters);
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
@@ -1270,7 +1264,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 === undefined ? '' : ` (default: ${this._escapeSpecialChars(jsDoc.default)})`}\n${
`/**\n * ${this._fixLinkTags(jsDoc.description) ?? ''}\n${
'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\n`).join('') : ''
}${'readonly' in jsDoc && jsDoc.readonly ? ' * @readonly\n' : ''}${
'deprecated' in jsDoc && jsDoc.deprecated
@@ -1348,7 +1342,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 === undefined ? '' : `\n * @defaultValue ${this._escapeSpecialChars(jsDoc.default)}`}\n${
`/**\n * ${this._fixLinkTags(jsDoc.description) ?? ''}\n${
'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\n`).join('') : ''
}${'readonly' in jsDoc && jsDoc.readonly ? ' * @readonly\n' : ''}${
'deprecated' in jsDoc && jsDoc.deprecated
@@ -1516,17 +1510,15 @@ export class ApiModelGenerator {
const excerptTokens: IExcerptToken[] = [
{
kind: ExcerptTokenKind.Content,
text: `public on(eventName: '${name}', listener: (${
jsDoc.params?.length
? `${jsDoc.params[0]?.name}${jsDoc.params[0]?.optional ? '?' : ''}: `
: ') => void): this;'
text: `on('${name}', (${
jsDoc.params?.length ? `${jsDoc.params[0]?.name}${jsDoc.params[0]?.nullable ? '?' : ''}: ` : ') => {})'
}`,
},
];
const parameters: IApiParameterOptions[] = [];
for (let index = 0; index < (jsDoc.params?.length ?? 0) - 1; index++) {
const parameter = jsDoc.params![index]!;
const newTokens = this._mapVarType(parameter.type, parameter.nullable);
const newTokens = this._mapVarType(parameter.type);
parameters.push({
parameterName: parameter.name,
parameterTypeTokenRange: {
@@ -1535,7 +1527,6 @@ export class ApiModelGenerator {
},
isOptional: Boolean(parameter.optional),
isRest: parameter.name.startsWith('...'),
defaultValue: parameter.default?.toString(),
});
excerptTokens.push(...newTokens);
excerptTokens.push({
@@ -1546,7 +1537,7 @@ export class ApiModelGenerator {
if (jsDoc.params?.length) {
const parameter = jsDoc.params![jsDoc.params.length - 1]!;
const newTokens = this._mapVarType(parameter.type, parameter.nullable);
const newTokens = this._mapVarType(parameter.type);
parameters.push({
parameterName: parameter.name,
parameterTypeTokenRange: {
@@ -1555,12 +1546,11 @@ export class ApiModelGenerator {
},
isOptional: Boolean(parameter.optional),
isRest: parameter.name.startsWith('...'),
defaultValue: parameter.default?.toString(),
});
excerptTokens.push(...newTokens);
excerptTokens.push({
kind: ExcerptTokenKind.Content,
text: `) => void): this;`,
text: `) => {})`,
});
}
@@ -1648,7 +1638,6 @@ export class ApiModelGenerator {
private _captureParameters(
nodesToCapture: IExcerptBuilderNodeToCapture[],
parameterNodes: ts.NodeArray<ts.ParameterDeclaration>,
jsDoc?: DocgenParamJson[] | undefined,
): IApiParameterOptions[] {
const parameters: IApiParameterOptions[] = [];
for (const parameter of parameterNodes) {
@@ -1659,9 +1648,6 @@ 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(),
});
}
@@ -1760,14 +1746,6 @@ export class ApiModelGenerator {
return sourceLocation;
}
private _escapeSpecialChars(input: boolean | number | string) {
if (typeof input !== 'string') {
return input;
}
return input.replaceAll(/(?<char>[@{}])/g, '\\$<char>');
}
private _fixLinkTags(input?: string): string | undefined {
return input
?.replaceAll(linkRegEx, (_match, _p1, _p2, _p3, _p4, _p5, _offset, _string, groups) => {
@@ -1787,7 +1765,7 @@ export class ApiModelGenerator {
.replaceAll('* ', '\n * * ');
}
private _mapVarType(typey: DocgenVarTypeJson, nullable?: boolean): IExcerptToken[] {
private _mapVarType(typey: DocgenVarTypeJson): IExcerptToken[] {
const mapper = Array.isArray(typey) ? typey : (typey.types ?? []);
const lookup: { [K in ts.SyntaxKind]?: string } = {
[ts.SyntaxKind.ClassDeclaration]: 'class',
@@ -1830,22 +1808,7 @@ export class ApiModelGenerator {
{ kind: ExcerptTokenKind.Content, text: symbol ?? '' },
];
}, []);
return index === 0
? mapper.length === 1 && (nullable || ('nullable' in typey && typey.nullable))
? [
...result,
{ kind: ExcerptTokenKind.Content, text: ' | ' },
{ kind: ExcerptTokenKind.Reference, text: 'null' },
]
: result
: index === mapper.length - 1 && (nullable || ('nullable' in typey && typey.nullable))
? [
{ kind: ExcerptTokenKind.Content, text: ' | ' },
...result,
{ kind: ExcerptTokenKind.Content, text: ' | ' },
{ kind: ExcerptTokenKind.Reference, text: 'null' },
]
: [{ kind: ExcerptTokenKind.Content, text: ' | ' }, ...result];
return index === 0 ? result : [{ kind: ExcerptTokenKind.Content, text: ' | ' }, ...result];
})
.filter((excerpt) => excerpt.text.length);
}
@@ -1860,7 +1823,7 @@ export class ApiModelGenerator {
isOptional: Boolean(prop.nullable),
isReadonly: Boolean(prop.readonly),
docComment: this._tsDocParser.parseString(
`/**\n * ${this._fixLinkTags(prop.description) ?? ''}\n${prop.default ? ` * @defaultValue ${this._escapeSpecialChars(prop.default)}\n` : ''}${
`/**\n * ${this._fixLinkTags(prop.description) ?? ''}\n${
prop.see?.map((see) => ` * @see ${see}\n`).join('') ?? ''
}${prop.readonly ? ' * @readonly\n' : ''} */`,
).docComment,
@@ -1872,7 +1835,7 @@ export class ApiModelGenerator {
}${prop.name} :`,
},
...mappedVarType,
{ kind: ExcerptTokenKind.Content, text: `${prop.default ? ` = ${prop.default}` : ''};` },
{ kind: ExcerptTokenKind.Content, text: ';' },
],
propertyTypeTokenRange: { startIndex: 1, endIndex: 1 + mappedVarType.length },
releaseTag: prop.access === 'private' ? ReleaseTag.Internal : ReleaseTag.Public,
@@ -1895,7 +1858,6 @@ 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(),
};
}
@@ -1920,7 +1882,7 @@ export class ApiModelGenerator {
excerptTokens.push(...newTokens);
excerptTokens.push({
kind: ExcerptTokenKind.Content,
text: `${method.params![index]!.default ? ` = ${method.params![index]!.default}` : ''}, ${method.params![index + 1]!.name}${
text: `, ${method.params![index + 1]!.name}${
method.params![index + 1]!.nullable || method.params![index + 1]!.optional ? '?' : ''
}: `,
});
@@ -1930,10 +1892,7 @@ 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: `${method.params![method.params.length - 1]!.default ? ` = ${method.params![method.params.length - 1]!.default}` : ''}): `,
});
excerptTokens.push({ kind: ExcerptTokenKind.Content, text: `): ` });
}
const returnTokens = this._mapVarType(method.returns?.[0] ?? []);

View File

@@ -9,8 +9,7 @@
<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://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>
<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>
@@ -24,7 +23,7 @@
## Installation
**Node.js 20 or newer is required.**
**Node.js 18 or newer is required.**
```sh
npm install @discordjs/brokers

View File

@@ -30,10 +30,8 @@ body = """
{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\
{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\
{% if commit.breaking %}\
{% for footer in commit.footers %}\
{% if footer.breaking %}\
\n{% raw %} {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\
{% endif %}\
{% for breakingChange in commit.footers %}\
\n{% raw %} {% endraw %}- **{{ breakingChange.token }}{{ breakingChange.separator }}** {{ breakingChange.value }}\
{% endfor %}\
{% endif %}\
{% endfor %}

View File

@@ -89,7 +89,7 @@
"vitest": "^2.0.5"
},
"engines": {
"node": ">=20"
"node": ">=18"
},
"publishConfig": {
"access": "public",

View File

@@ -9,8 +9,7 @@
<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://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>
<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>
@@ -24,7 +23,7 @@
## Installation
**Node.js 18 or newer is required.**
**Node.js 16.11.0 or newer is required.**
```sh
npm install @discordjs/builders

View File

@@ -166,7 +166,7 @@ describe('Context Menu Commands', () => {
});
describe('integration types', () => {
test('GIVEN a builder with valid integration types THEN does not throw an error', () => {
test('GIVEN a builder with valid integraton types THEN does not throw an error', () => {
expect(() =>
getBuilder().setIntegrationTypes([
ApplicationIntegrationType.GuildInstall,

View File

@@ -565,7 +565,7 @@ describe('Slash Commands', () => {
});
describe('integration types', () => {
test('GIVEN a builder with valid integration types THEN does not throw an error', () => {
test('GIVEN a builder with valid integraton types THEN does not throw an error', () => {
expect(() =>
getBuilder().setIntegrationTypes([
ApplicationIntegrationType.GuildInstall,

View File

@@ -30,10 +30,8 @@ body = """
{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\
{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\
{% if commit.breaking %}\
{% for footer in commit.footers %}\
{% if footer.breaking %}\
\n{% raw %} {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\
{% endif %}\
{% for breakingChange in commit.footers %}\
\n{% raw %} {% endraw %}- **{{ breakingChange.token }}{{ breakingChange.separator }}** {{ breakingChange.value }}\
{% endfor %}\
{% endif %}\
{% endfor %}

View File

@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@discordjs/builders",
"version": "1.9.0",
"version": "1.10.0",
"description": "A set of builders that you can use when creating your bot",
"scripts": {
"test": "vitest run",
@@ -68,7 +68,7 @@
"@discordjs/formatters": "workspace:^",
"@discordjs/util": "workspace:^",
"@sapphire/shapeshift": "^4.0.0",
"discord-api-types": "^0.37.119",
"discord-api-types": "^0.37.114",
"fast-deep-equal": "^3.1.3",
"ts-mixer": "^6.0.4",
"tslib": "^2.6.3"
@@ -91,7 +91,7 @@
"vitest": "^2.0.5"
},
"engines": {
"node": ">=18"
"node": ">=16.11.0"
},
"publishConfig": {
"access": "public",

View File

@@ -83,7 +83,7 @@ export class StringSelectMenuBuilder extends BaseSelectMenuBuilder<APIStringSele
*
* @remarks
* This method behaves similarly
* to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/slice | Array.prototype.splice()}.
* to {@link https://developer.mozilla.org/en-US/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:

View File

@@ -125,7 +125,7 @@ export class EmbedBuilder {
*
* @remarks
* This method behaves similarly
* to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.
* to {@link https://developer.mozilla.org/en-US/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.

View File

@@ -9,8 +9,7 @@
<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://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>
<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>

View File

@@ -30,10 +30,8 @@ body = """
{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\
{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\
{% if commit.breaking %}\
{% for footer in commit.footers %}\
{% if footer.breaking %}\
\n{% raw %} {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\
{% endif %}\
{% for breakingChange in commit.footers %}\
\n{% raw %} {% endraw %}- **{{ breakingChange.token }}{{ breakingChange.separator }}** {{ breakingChange.value }}\
{% endfor %}\
{% endif %}\
{% endfor %}

View File

@@ -2,41 +2,6 @@
All notable changes to this project will be documented in this file.
# [@discordjs/core@2.2.2](https://github.com/discordjs/discord.js/compare/@discordjs/core@2.2.1...@discordjs/core@2.2.2) - (2025-09-10)
## Bug Fixes
- **users:** Correct type for editing current guild member (#11098) ([9ae7377](https://github.com/discordjs/discord.js/commit/9ae737708b24400320a2da4a85a6c977475a05a5))
- **guild:** Creating a template actually creates a template (#11030) ([ac6ff15](https://github.com/discordjs/discord.js/commit/ac6ff15b7dc4a88753b7cfdf1bca1b4bcc1cc260))
## Documentation
- **guild:** Deprecate API related to guild ownership ([6fb0b1c](https://github.com/discordjs/discord.js/commit/6fb0b1cef6e479be3d47370438d8a588a7c2b850))
# [@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

View File

@@ -9,8 +9,7 @@
<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://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>
<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>
@@ -24,7 +23,7 @@
## Installation
**Node.js 20 or newer is required.**
**Node.js 18 or newer is required.**
```sh
npm install @discordjs/core

View File

@@ -1,6 +1,5 @@
{
"extends": "../../api-extractor.json",
"bundledPackages": ["discord-api-types"],
"docModel": {
"projectFolderUrl": "https://github.com/discordjs/discord.js/tree/main/packages/core"
}

View File

@@ -30,10 +30,8 @@ body = """
{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\
{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\
{% if commit.breaking %}\
{% for footer in commit.footers %}\
{% if footer.breaking %}\
\n{% raw %} {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\
{% endif %}\
{% for breakingChange in commit.footers %}\
\n{% raw %} {% endraw %}- **{{ breakingChange.token }}{{ breakingChange.separator }}** {{ breakingChange.value }}\
{% endfor %}\
{% endif %}\
{% endfor %}

View File

@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@discordjs/core",
"version": "2.2.2",
"version": "2.0.0",
"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.38.24"
"discord-api-types": "^0.37.114"
},
"devDependencies": {
"@discordjs/api-extractor": "workspace:^",
@@ -90,7 +90,7 @@
"vitest": "^2.0.5"
},
"engines": {
"node": ">=20"
"node": ">=18"
},
"publishConfig": {
"access": "public",

View File

@@ -45,7 +45,7 @@ export class ChannelsAPI {
/**
* Sends a message in a channel
*
* @see {@link https://discord.com/developers/docs/resources/message#create-message}
* @see {@link https://discord.com/developers/docs/resources/channel#create-message}
* @param channelId - The id of the channel to send the message in
* @param body - The data for sending the message
* @param options - The options for sending the message
@@ -65,7 +65,7 @@ export class ChannelsAPI {
/**
* Edits a message
*
* @see {@link https://discord.com/developers/docs/resources/message#edit-message}
* @see {@link https://discord.com/developers/docs/resources/channel#edit-message}
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to edit
* @param body - The data for editing the message
@@ -87,7 +87,7 @@ export class ChannelsAPI {
/**
* Fetches the reactions for a message
*
* @see {@link https://discord.com/developers/docs/resources/message#get-reactions}
* @see {@link https://discord.com/developers/docs/resources/channel#get-reactions}
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to get the reactions for
* @param emoji - The emoji to get the reactions for
@@ -110,7 +110,7 @@ export class ChannelsAPI {
/**
* Deletes a reaction for the current user
*
* @see {@link https://discord.com/developers/docs/resources/message#delete-own-reaction}
* @see {@link https://discord.com/developers/docs/resources/channel#delete-own-reaction}
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to delete the reaction for
* @param emoji - The emoji to delete the reaction for
@@ -130,7 +130,7 @@ export class ChannelsAPI {
/**
* Deletes a reaction for a user
*
* @see {@link https://discord.com/developers/docs/resources/message#delete-user-reaction}
* @see {@link https://discord.com/developers/docs/resources/channel#delete-user-reaction}
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to delete the reaction for
* @param emoji - The emoji to delete the reaction for
@@ -152,7 +152,7 @@ export class ChannelsAPI {
/**
* Deletes all reactions for a message
*
* @see {@link https://discord.com/developers/docs/resources/message#delete-all-reactions}
* @see {@link https://discord.com/developers/docs/resources/channel#delete-all-reactions}
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to delete the reactions for
* @param options - The options for deleting the reactions
@@ -168,7 +168,7 @@ export class ChannelsAPI {
/**
* Deletes all reactions of an emoji for a message
*
* @see {@link https://discord.com/developers/docs/resources/message#delete-all-reactions-for-emoji}
* @see {@link https://discord.com/developers/docs/resources/channel#delete-all-reactions-for-emoji}
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to delete the reactions for
* @param emoji - The emoji to delete the reactions for
@@ -186,7 +186,7 @@ export class ChannelsAPI {
/**
* Adds a reaction to a message
*
* @see {@link https://discord.com/developers/docs/resources/message#create-reaction}
* @see {@link https://discord.com/developers/docs/resources/channel#create-reaction}
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to add the reaction to
* @param emoji - The emoji to add the reaction with
@@ -223,13 +223,9 @@ export class ChannelsAPI {
public async edit(
channelId: Snowflake,
body: RESTPatchAPIChannelJSONBody,
{ signal, reason }: Pick<RequestData, 'reason' | 'signal'> = {},
{ signal }: Pick<RequestData, 'signal'> = {},
) {
return this.rest.patch(Routes.channel(channelId), {
reason,
body,
signal,
}) as Promise<RESTPatchAPIChannelResult>;
return this.rest.patch(Routes.channel(channelId), { body, signal }) as Promise<RESTPatchAPIChannelResult>;
}
/**
@@ -239,14 +235,14 @@ 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, reason }: Pick<RequestData, 'reason' | 'signal'> = {}) {
return this.rest.delete(Routes.channel(channelId), { signal, reason }) as Promise<RESTDeleteAPIChannelResult>;
public async delete(channelId: Snowflake, { signal }: Pick<RequestData, 'signal'> = {}) {
return this.rest.delete(Routes.channel(channelId), { signal }) as Promise<RESTDeleteAPIChannelResult>;
}
/**
* Fetches the messages of a channel
*
* @see {@link https://discord.com/developers/docs/resources/message#get-channel-messages}
* @see {@link https://discord.com/developers/docs/resources/channel#get-channel-messages}
* @param channelId - The id of the channel to fetch messages from
* @param query - The query options for fetching messages
* @param options - The options for fetching the messages
@@ -303,7 +299,7 @@ export class ChannelsAPI {
/**
* Deletes a message
*
* @see {@link https://discord.com/developers/docs/resources/message#delete-message}
* @see {@link https://discord.com/developers/docs/resources/channel#delete-message}
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to delete
* @param options - The options for deleting the message
@@ -319,7 +315,7 @@ export class ChannelsAPI {
/**
* Bulk deletes messages
*
* @see {@link https://discord.com/developers/docs/resources/message#bulk-delete-messages}
* @see {@link https://discord.com/developers/docs/resources/channel#bulk-delete-messages}
* @param channelId - The id of the channel the messages are in
* @param messageIds - The ids of the messages to delete
* @param options - The options for deleting the messages
@@ -335,7 +331,7 @@ export class ChannelsAPI {
/**
* Fetches a message
*
* @see {@link https://discord.com/developers/docs/resources/message#get-channel-message}
* @see {@link https://discord.com/developers/docs/resources/channel#get-channel-message}
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to fetch
* @param options - The options for fetching the message
@@ -349,7 +345,7 @@ export class ChannelsAPI {
/**
* Crossposts a message
*
* @see {@link https://discord.com/developers/docs/resources/message#crosspost-message}
* @see {@link https://discord.com/developers/docs/resources/channel#crosspost-message}
* @param channelId - The id of the channel the message is in
* @param messageId - The id of the message to crosspost
* @param options - The options for crossposting the message
@@ -445,19 +441,18 @@ export class ChannelsAPI {
channelId: Snowflake,
body: RESTPostAPIChannelThreadsJSONBody,
messageId?: Snowflake,
{ signal, reason }: Pick<RequestData, 'reason' | 'signal'> = {},
{ signal }: Pick<RequestData, 'signal'> = {},
) {
return this.rest.post(Routes.threads(channelId, messageId), {
body,
signal,
reason,
}) as Promise<RESTPostAPIChannelThreadsResult>;
}
/**
* Creates a new forum post
*
* @see {@link https://discord.com/developers/docs/resources/channel#start-thread-in-forum-or-media-channel}
* @see {@link https://discord.com/developers/docs/resources/channel#start-thread-in-forum-channel}
* @param channelId - The id of the forum channel to start the thread in
* @param body - The data for starting the thread
* @param options - The options for starting the thread
@@ -465,7 +460,7 @@ export class ChannelsAPI {
public async createForumThread(
channelId: Snowflake,
{ message, ...optionsBody }: StartForumThreadOptions,
{ signal, reason }: Pick<RequestData, 'reason' | 'signal'> = {},
{ signal }: Pick<RequestData, 'signal'> = {},
) {
const { files, ...messageBody } = message;
@@ -474,12 +469,7 @@ export class ChannelsAPI {
message: messageBody,
};
return this.rest.post(Routes.threads(channelId), {
files,
body,
reason,
signal,
}) as Promise<APIThreadChannel>;
return this.rest.post(Routes.threads(channelId), { files, body, signal }) as Promise<APIThreadChannel>;
}
/**

View File

@@ -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
@@ -166,7 +166,6 @@ export class GuildsAPI {
* @see {@link https://discord.com/developers/docs/resources/guild#create-guild}
* @param body - The guild to create
* @param options - The options for creating the guild
* @deprecated API related to guild ownership may no longer be used.
*/
public async create(body: RESTPostAPIGuildsJSONBody, { signal }: Pick<RequestData, 'signal'> = {}) {
return this.rest.post(Routes.guilds(), { body, signal }) as Promise<RESTPostAPIGuildsResult>;
@@ -198,10 +197,9 @@ export class GuildsAPI {
* @see {@link https://discord.com/developers/docs/resources/guild#delete-guild}
* @param guildId - The id of the guild to delete
* @param options - The options for deleting this guild
* @deprecated API related to guild ownership may no longer be used.
*/
public async delete(guildId: Snowflake, { signal }: Pick<RequestData, 'signal'> = {}) {
await this.rest.delete(Routes.guild(guildId), { signal });
public async delete(guildId: Snowflake, { signal, reason }: Pick<RequestData, 'reason' | 'signal'> = {}) {
await this.rest.delete(Routes.guild(guildId), { reason, signal });
}
/**
@@ -493,7 +491,6 @@ export class GuildsAPI {
* @param guildId - The id of the guild to edit the MFA level for
* @param level - The new MFA level
* @param options - The options for editing the MFA level
* @deprecated API related to guild ownership may no longer be used.
*/
public async editMFALevel(
guildId: Snowflake,
@@ -1290,16 +1287,16 @@ export class GuildsAPI {
* Creates a new template
*
* @see {@link https://discord.com/developers/docs/resources/guild-template#create-guild-template}
* @param guildId - The id of the guild
* @param templateCode - The code of the template
* @param body - The data for creating the template
* @param options - The options for creating the template
*/
public async createTemplate(
guildId: Snowflake,
templateCode: string,
body: RESTPostAPIGuildTemplatesJSONBody,
{ signal }: Pick<RequestData, 'signal'> = {},
) {
return this.rest.post(Routes.guildTemplates(guildId), { body, signal }) as Promise<RESTPostAPIGuildTemplatesResult>;
return this.rest.post(Routes.template(templateCode), { body, signal }) as Promise<RESTPostAPIGuildTemplatesResult>;
}
/**

View File

@@ -258,7 +258,7 @@ export class InteractionsAPI {
* @param interactionId - The id of the interaction
* @param interactionToken - The token of the interaction
* @param options - The options for sending the premium required response
* @deprecated Sending a premium-style button is the new Discord behavior.
* @deprecated Sending a premium-style button is the new Discord behaviour.
*/
public async sendPremiumRequired(
interactionId: Snowflake,

View File

@@ -44,7 +44,7 @@ export class OAuth2API {
{ signal }: Pick<RequestData, 'signal'> = {},
) {
return this.rest.post(Routes.oauth2TokenExchange(), {
body: makeURLSearchParams<RESTPostOAuth2AccessTokenURLEncodedData>(body),
body: makeURLSearchParams(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<RESTPostOAuth2RefreshTokenURLEncodedData>(body),
body: makeURLSearchParams(body),
passThroughBody: true,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',

View File

@@ -10,9 +10,9 @@ import {
type RESTGetAPICurrentUserResult,
type RESTGetAPIUserResult,
type RESTGetCurrentUserGuildMemberResult,
type RESTPatchAPICurrentGuildMemberJSONBody,
type RESTPatchAPICurrentUserJSONBody,
type RESTPatchAPICurrentUserResult,
type RESTPatchAPIGuildMemberJSONBody,
type RESTPatchAPIGuildMemberResult,
type RESTPostAPICurrentUserCreateDMChannelResult,
type RESTPutAPICurrentUserApplicationRoleConnectionJSONBody,
@@ -101,7 +101,7 @@ export class UsersAPI {
*/
public async editCurrentGuildMember(
guildId: Snowflake,
body: RESTPatchAPICurrentGuildMemberJSONBody = {},
body: RESTPatchAPIGuildMemberJSONBody = {},
{ reason, signal }: Pick<RequestData, 'reason' | 'signal'> = {},
) {
return this.rest.patch(Routes.guildMember(guildId, '@me'), {

View File

@@ -9,7 +9,6 @@ import {
type RESTPatchAPIWebhookJSONBody,
type RESTPatchAPIWebhookResult,
type RESTPatchAPIWebhookWithTokenMessageJSONBody,
type RESTPatchAPIWebhookWithTokenMessageQuery,
type RESTPatchAPIWebhookWithTokenMessageResult,
type RESTPostAPIWebhookWithTokenGitHubQuery,
type RESTPostAPIWebhookWithTokenJSONBody,
@@ -128,14 +127,13 @@ 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, with_components }),
query: makeURLSearchParams({ wait, thread_id }),
files,
body,
auth: false,
@@ -234,14 +232,13 @@ export class WebhooksAPI {
messageId: Snowflake,
{
thread_id,
with_components,
files,
...body
}: RESTPatchAPIWebhookWithTokenMessageJSONBody & RESTPatchAPIWebhookWithTokenMessageQuery & { files?: RawFile[] },
}: RESTPatchAPIWebhookWithTokenMessageJSONBody & { files?: RawFile[]; thread_id?: string },
{ signal }: Pick<RequestData, 'signal'> = {},
) {
return this.rest.patch(Routes.webhookMessage(id, token, messageId), {
query: makeURLSearchParams({ thread_id, with_components }),
query: makeURLSearchParams({ thread_id }),
auth: false,
body,
signal,

View File

@@ -7,7 +7,6 @@
<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>

View File

@@ -30,10 +30,8 @@ body = """
{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\
{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\
{% if commit.breaking %}\
{% for footer in commit.footers %}\
{% if footer.breaking %}\
\n{% raw %} {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\
{% endif %}\
{% for breakingChange in commit.footers %}\
\n{% raw %} {% endraw %}- **{{ breakingChange.token }}{{ breakingChange.separator }}** {{ breakingChange.value }}\
{% endfor %}\
{% endif %}\
{% endfor %}

View File

@@ -83,7 +83,7 @@
"no-void": "error",
"no-warning-comments": "warn",
"prefer-promise-reject-errors": "error",
"require-await": "off",
"require-await": "warn",
"wrap-iife": "error",
"yoda": "error",

View File

@@ -1,5 +1,5 @@
{
"$schema": "https://json.schemastore.org/lintstagedrc.schema.json",
"*": "prettier --ignore-unknown --write",
"{src/**,typings/**,scripts/**}.{mjs,js,ts}": "cross-env ESLINT_USE_FLAT_CONFIG=false eslint --ext mjs,js,ts --fix"
"{src/**,test/**,typings/**,scripts/**}.{mjs,js,ts}": "cross-env ESLINT_USE_FLAT_CONFIG=false eslint --ext mjs,js,ts --fix"
}

View File

@@ -2,272 +2,6 @@
All notable changes to this project will be documented in this file.
# [14.22.1](https://github.com/discordjs/discord.js/compare/14.22.0...14.22.1) - (2025-08-22)
## Bug Fixes
- **GuildChannel:** Account for everyone base permissions (#11053) ([ecef7bd](https://github.com/discordjs/discord.js/commit/ecef7bdf22cc3e7c1fc47d828a55f6139672b2a8))
# [14.22.0](https://github.com/discordjs/discord.js/compare/14.21.0...14.22.0) - (2025-08-20)
## Bug Fixes
- Remove trailing `color` references (#11007) ([b532df6](https://github.com/discordjs/discord.js/commit/b532df61ed346e2289831f2905984583a53d3fa5))
- **Emoji:** Remove incorrect nullables, add `ApplicationEmoji#available` (#10990) ([90d3b28](https://github.com/discordjs/discord.js/commit/90d3b282684f5a4bbf9ce2672fa5efd5ec802e95))
- **GuildChannelManager:** Properly resolve avatar for createWebhook (#10772) ([63f5261](https://github.com/discordjs/discord.js/commit/63f5261f4c351cd1b6befca1163254300f7424f4))
- **Message:** Forwarded messages are not `crosspostable` (#10821) ([b36b751](https://github.com/discordjs/discord.js/commit/b36b751bde5f5de286d748465619147619959d4f))
- **DirectoryChannel:** Export class (#10985) ([51ceb20](https://github.com/discordjs/discord.js/commit/51ceb203fa218accab47f604f91f74b49af7e51f))
- **Events:** `WebhooksUpdate` enum value (#10970) ([1404e32](https://github.com/discordjs/discord.js/commit/1404e328492549f4a17ab997eb648f3263e8ec25))
## Documentation
- Remove hardcoded locale from links (#10794) ([5be774d](https://github.com/discordjs/discord.js/commit/5be774db641b60669505645861d721200d335a7b))
- **ApplicationCommand:** Incorrect method in example (#10837) ([040c66a](https://github.com/discordjs/discord.js/commit/040c66ae15fd3cc7cb40bdbb5384ede445c40973))
## Features
- Support user guilds (#10995) ([baa08b8](https://github.com/discordjs/discord.js/commit/baa08b8fbb64abd8265890413c95f81e2c61303f))
- **MessageManager:** New pinned messages routes (#10993) ([f469f74](https://github.com/discordjs/discord.js/commit/f469f74acaa14f126fd02af4a032ca8e56dbb534))
- `fetchPinned()` has been renamed to `fetchPins()`, which is a paginated endpoint to fetch pinned messages.
- **User:** Add `collectibles` (#10939) ([8ac0e1e](https://github.com/discordjs/discord.js/commit/8ac0e1e5d6df9c51fd3a41d9f8c9dbe8f786229a))
- Role gradient colours (#10986) ([9d6fdf8](https://github.com/discordjs/discord.js/commit/9d6fdf8979d29787a13912cfa55f1ff3961c6b68))
- Support animated WebP (#10987) ([cafe58b](https://github.com/discordjs/discord.js/commit/cafe58b3bd9defb5050a7a90bd07568f3b509c89))
## Refactor
- Deprecate `ready` event in favor of `clientReady` (#10969) ([82378fc](https://github.com/discordjs/discord.js/commit/82378fc2e8f4fd7e56b5a80eb6a6d3a8315e388e))
- **ThreadChannel:** Remove trimming of name (#10984) ([d4f742e](https://github.com/discordjs/discord.js/commit/d4f742e99e31b4eb9e84afce3bab48ed549f8ae3))
## Typings
- **Invite:** Approximate fields should be nullable (#10997) ([d60e0bf](https://github.com/discordjs/discord.js/commit/d60e0bf30bac05921063d010fab253ca829ae3bb))
- **ModalSubmitFields:** Fix `fields` type (#10816) ([500712d](https://github.com/discordjs/discord.js/commit/500712d5eaef1a75133e088e0f260842d12f3419))
- **InteractionCallbackResponse:** Add missing InGuild generic (#10963) ([19e74b1](https://github.com/discordjs/discord.js/commit/19e74b153317cf8b910317c56beb95a698acc00c))
# [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
- **BaseInteraction:** Add missing props (#10517) ([6c77fee](https://github.com/discordjs/discord.js/commit/6c77fee41b1aabc243bff623debd157a4c7fad6a)) by @monbrey
- `GuildChannel#guildId` not being patched to `undefined` (#10505) ([2adee06](https://github.com/discordjs/discord.js/commit/2adee06b6e92b7854ebb1c2bfd04940aab68dd10)) by @Qjuh
## Typings
- **MessageEditOptions:** Omit `poll` (#10509) ([665bf14](https://github.com/discordjs/discord.js/commit/665bf1486aec62e9528f5f7b5a6910ae6b5a6c9c)) by @TAEMBO
# [14.16.2](https://github.com/discordjs/discord.js/compare/14.16.1...14.16.2) - (2024-09-12)
## Bug Fixes
- **ApplicationCommand:** Incorrect comparison in equals method (#10497) ([3c74aa2](https://github.com/discordjs/discord.js/commit/3c74aa204909323ff6d05991438bee2c583e838b)) by @monbrey
- Type guard for sendable text-based channels (#10482) ([dea6840](https://github.com/discordjs/discord.js/commit/dea68400a38edb90b8b4242d64be14968943130d)) by @vladfrangu
## Documentation
- Update discord documentation links (#10484) ([799fa54](https://github.com/discordjs/discord.js/commit/799fa54fa4434144855be2f7a0bbac6ff8ce9d0b)) by @sdanialraza
- **Message:** Mark `interaction` as deprecated (#10481) ([c13f18e](https://github.com/discordjs/discord.js/commit/c13f18e90eb6eb315397c095e948993856428757)) by @sdanialraza
- **ApplicationEmojiManager:** Fix fetch example (#10480) ([4594896](https://github.com/discordjs/discord.js/commit/4594896b5404c6a34e07544951c59ff8f3657184)) by @sdanialraza
## Typings
- Export GroupDM helper type (#10478) ([aff772c](https://github.com/discordjs/discord.js/commit/aff772c7aa3b3de58780a94588d1f3576a434f32)) by @Qjuh
# [14.16.1](https://github.com/discordjs/discord.js/compare/14.16.0...14.16.1) - (2024-09-02)
## Bug Fixes
- **Message:** Reacting returning undefined (#10475) ([9257a09](https://github.com/discordjs/discord.js/commit/9257a09abbf80558ed2d5d209a2f6bd2a4b3d799)) by @vladfrangu
- **Transformers:** Pass client to recursive call (#10474) ([4810f7c](https://github.com/discordjs/discord.js/commit/4810f7c8637dacf77d0442bd84e0d579e1f1d3bd)) by @SpaceEEC
# [14.16.0](https://github.com/discordjs/discord.js/compare/14.15.3...14.16.0) - (2024-09-01)
## Bug Fixes

View File

@@ -9,8 +9,7 @@
<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://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>
<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>
@@ -30,7 +29,7 @@ discord.js is a powerful [Node.js](https://nodejs.org) module that allows you to
## Installation
**Node.js 18 or newer is required.**
**Node.js 16.11.0 or newer is required.**
```sh
npm install discord.js
@@ -43,6 +42,7 @@ bun add discord.js
- [zlib-sync](https://www.npmjs.com/package/zlib-sync) for WebSocket data compression and inflation (`npm install zlib-sync`)
- [bufferutil](https://www.npmjs.com/package/bufferutil) for a much faster WebSocket connection (`npm install bufferutil`)
- [utf-8-validate](https://www.npmjs.com/package/utf-8-validate) in combination with `bufferutil` for much faster WebSocket processing (`npm install utf-8-validate`)
- [@discordjs/voice](https://www.npmjs.com/package/@discordjs/voice) for interacting with the Discord Voice API (`npm install @discordjs/voice`)
## Example usage

View File

@@ -1,15 +1,6 @@
{
"extends": "../../api-extractor.json",
"mainEntryPointFilePath": "<projectFolder>/typings/index.d.ts",
"bundledPackages": [
"discord-api-types",
"@discordjs/collection",
"@discordjs/builders",
"@discordjs/formatters",
"@discordjs/rest",
"@discordjs/util",
"@discordjs/ws"
],
"docModel": {
"projectFolderUrl": "https://github.com/discordjs/discord.js/tree/main/packages/discord.js"
}

View File

@@ -30,10 +30,8 @@ body = """
{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\
{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\
{% if commit.breaking %}\
{% for footer in commit.footers %}\
{% if footer.breaking %}\
\n{% raw %} {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\
{% endif %}\
{% for breakingChange in commit.footers %}\
\n{% raw %} {% endraw %}- **{{ breakingChange.token }}{{ breakingChange.separator }}** {{ breakingChange.value }}\
{% endfor %}\
{% endif %}\
{% endfor %}
@@ -69,7 +67,8 @@ commit_parsers = [
{ body = ".*security", group = "Security"},
]
filter_commits = true
tag_pattern = "^[0-9]+"
tag_pattern = "[0-9]*"
skip_tags = "v[0-9]*|@discordjs*"
ignore_tags = ""
topo_order = false
sort_commits = "newest"

View File

@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "discord.js",
"version": "14.22.1",
"version": "14.16.0",
"description": "A powerful library for interacting with the Discord API",
"scripts": {
"test": "pnpm run docs:test && pnpm run test:typescript",
@@ -36,8 +36,7 @@
},
"files": [
"src",
"typings/*.d.ts",
"typings/*.d.mts"
"typings"
],
"contributors": [
"Crawl <icrawltogo@gmail.com>",
@@ -66,19 +65,18 @@
"homepage": "https://discord.js.org",
"funding": "https://github.com/discordjs/discord.js?sponsor",
"dependencies": {
"@discordjs/builders": "^1.11.2",
"@discordjs/builders": "workspace:^",
"@discordjs/collection": "1.5.3",
"@discordjs/formatters": "^0.6.1",
"@discordjs/formatters": "workspace:^",
"@discordjs/rest": "workspace:^",
"@discordjs/util": "workspace:^",
"@discordjs/ws": "^1.2.3",
"@discordjs/ws": "1.1.1",
"@sapphire/snowflake": "3.5.3",
"discord-api-types": "^0.38.24",
"discord-api-types": "^0.37.114",
"fast-deep-equal": "3.1.3",
"lodash.snakecase": "4.1.1",
"magic-bytes.js": "^1.10.0",
"tslib": "^2.6.3",
"undici": "6.21.3"
"undici": "6.19.8"
},
"devDependencies": {
"@discordjs/api-extractor": "workspace:^",
@@ -100,7 +98,7 @@
"typescript": "~5.5.4"
},
"engines": {
"node": ">=18"
"node": ">=16.11.0"
},
"publishConfig": {
"provenance": true

View File

@@ -36,14 +36,12 @@ async function writeClientActionImports() {
for (const file of (await readdir(actionsDirectory)).sort()) {
if (file === 'Action.js' || file === 'ActionsManager.js') continue;
const actionName = file.slice(0, -3);
lines.push(` this.${actionName} = this.load(require('./${file}'));`);
lines.push(` this.register(require('./${file.slice(0, -3)}'));`);
}
lines.push(' }\n');
lines.push(' load(Action) {');
lines.push(' return new Action(this.client);');
lines.push(' register(Action) {');
lines.push(" this[Action.name.replace(/Action$/, '')] = new Action(this.client);");
lines.push(' }');
lines.push('}\n');
lines.push('module.exports = ActionsManager;\n');

View File

@@ -18,7 +18,6 @@ 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');
@@ -108,20 +107,20 @@ class Client extends BaseClient {
: null;
/**
* The user manager of this client
* All of the {@link User} objects that have been cached at any point, mapped by their ids
* @type {UserManager}
*/
this.users = new UserManager(this);
/**
* A manager of all the guilds the client is currently handling -
* All of the guilds the client is currently handling, mapped by their ids -
* as long as sharding isn't being used, this will be *every* guild the bot is a member of
* @type {GuildManager}
*/
this.guilds = new GuildManager(this);
/**
* All of the {@link BaseChannel}s that the client is currently handling -
* All of the {@link BaseChannel}s that the client is currently handling, mapped by their ids -
* as long as sharding isn't being used, this will be *every* channel in *every* guild the bot
* is a member of. Note that DM channels will not be initially cached, and thus not be present
* in the Manager without their explicit fetching or use.
@@ -175,7 +174,7 @@ class Client extends BaseClient {
}
/**
* A manager of all the custom emojis that the client has access to
* All custom emojis that the client has access to, mapped by their ids
* @type {BaseGuildEmojiManager}
* @readonly
*/
@@ -277,6 +276,7 @@ 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,19 +390,6 @@ 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
@@ -522,7 +509,7 @@ class Client extends BaseClient {
}
/**
* Calls {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/eval} on a script
* Calls {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval} on a script
* with the client as `this`.
* @param {string} script Script to eval
* @returns {*}
@@ -604,7 +591,7 @@ module.exports = Client;
*/
/**
* A {@link https://docs.x.com/resources/fundamentals/x-ids Twitter snowflake},
* A {@link https://developer.twitter.com/en/docs/twitter-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:
@@ -638,11 +625,6 @@ 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}

View File

@@ -1,8 +1,6 @@
'use strict';
const { Poll } = require('../../structures/Poll.js');
const { PollAnswer } = require('../../structures/PollAnswer.js');
const Partials = require('../../util/Partials.js');
const Partials = require('../../util/Partials');
/*
@@ -65,23 +63,6 @@ class GenericAction {
);
}
getPoll(data, message, channel) {
const includePollPartial = this.client.options.partials.includes(Partials.Poll);
const includePollAnswerPartial = this.client.options.partials.includes(Partials.PollAnswer);
if (message.partial && (!includePollPartial || !includePollAnswerPartial)) return null;
if (!message.poll && includePollPartial) {
message.poll = new Poll(this.client, data, message, channel);
}
if (message.poll && !message.poll.answers.has(data.answer_id) && includePollAnswerPartial) {
const pollAnswer = new PollAnswer(this.client, data, message.poll);
message.poll.answers.set(data.answer_id, pollAnswer);
}
return message.poll;
}
getReaction(data, message, user) {
const id = data.emoji.id ?? decodeURIComponent(data.emoji.name);
return this.getPayload(
@@ -130,14 +111,6 @@ class GenericAction {
getThreadMember(id, manager) {
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]]));
}
}
module.exports = GenericAction;

View File

@@ -11,74 +11,73 @@ class ActionsManager {
constructor(client) {
this.client = client;
this.ApplicationCommandPermissionsUpdate = this.load(require('./ApplicationCommandPermissionsUpdate.js'));
this.AutoModerationActionExecution = this.load(require('./AutoModerationActionExecution.js'));
this.AutoModerationRuleCreate = this.load(require('./AutoModerationRuleCreate.js'));
this.AutoModerationRuleDelete = this.load(require('./AutoModerationRuleDelete.js'));
this.AutoModerationRuleUpdate = this.load(require('./AutoModerationRuleUpdate.js'));
this.ChannelCreate = this.load(require('./ChannelCreate.js'));
this.ChannelDelete = this.load(require('./ChannelDelete.js'));
this.ChannelUpdate = this.load(require('./ChannelUpdate.js'));
this.EntitlementCreate = this.load(require('./EntitlementCreate.js'));
this.EntitlementDelete = this.load(require('./EntitlementDelete.js'));
this.EntitlementUpdate = this.load(require('./EntitlementUpdate.js'));
this.GuildAuditLogEntryCreate = this.load(require('./GuildAuditLogEntryCreate.js'));
this.GuildBanAdd = this.load(require('./GuildBanAdd.js'));
this.GuildBanRemove = this.load(require('./GuildBanRemove.js'));
this.GuildChannelsPositionUpdate = this.load(require('./GuildChannelsPositionUpdate.js'));
this.GuildDelete = this.load(require('./GuildDelete.js'));
this.GuildEmojiCreate = this.load(require('./GuildEmojiCreate.js'));
this.GuildEmojiDelete = this.load(require('./GuildEmojiDelete.js'));
this.GuildEmojiUpdate = this.load(require('./GuildEmojiUpdate.js'));
this.GuildEmojisUpdate = this.load(require('./GuildEmojisUpdate.js'));
this.GuildIntegrationsUpdate = this.load(require('./GuildIntegrationsUpdate.js'));
this.GuildMemberRemove = this.load(require('./GuildMemberRemove.js'));
this.GuildMemberUpdate = this.load(require('./GuildMemberUpdate.js'));
this.GuildRoleCreate = this.load(require('./GuildRoleCreate.js'));
this.GuildRoleDelete = this.load(require('./GuildRoleDelete.js'));
this.GuildRoleUpdate = this.load(require('./GuildRoleUpdate.js'));
this.GuildRolesPositionUpdate = this.load(require('./GuildRolesPositionUpdate.js'));
this.GuildScheduledEventCreate = this.load(require('./GuildScheduledEventCreate.js'));
this.GuildScheduledEventDelete = this.load(require('./GuildScheduledEventDelete.js'));
this.GuildScheduledEventUpdate = this.load(require('./GuildScheduledEventUpdate.js'));
this.GuildScheduledEventUserAdd = this.load(require('./GuildScheduledEventUserAdd.js'));
this.GuildScheduledEventUserRemove = this.load(require('./GuildScheduledEventUserRemove.js'));
this.GuildSoundboardSoundDelete = this.load(require('./GuildSoundboardSoundDelete.js'));
this.GuildStickerCreate = this.load(require('./GuildStickerCreate.js'));
this.GuildStickerDelete = this.load(require('./GuildStickerDelete.js'));
this.GuildStickerUpdate = this.load(require('./GuildStickerUpdate.js'));
this.GuildStickersUpdate = this.load(require('./GuildStickersUpdate.js'));
this.GuildUpdate = this.load(require('./GuildUpdate.js'));
this.InteractionCreate = this.load(require('./InteractionCreate.js'));
this.InviteCreate = this.load(require('./InviteCreate.js'));
this.InviteDelete = this.load(require('./InviteDelete.js'));
this.MessageCreate = this.load(require('./MessageCreate.js'));
this.MessageDelete = this.load(require('./MessageDelete.js'));
this.MessageDeleteBulk = this.load(require('./MessageDeleteBulk.js'));
this.MessagePollVoteAdd = this.load(require('./MessagePollVoteAdd.js'));
this.MessagePollVoteRemove = this.load(require('./MessagePollVoteRemove.js'));
this.MessageReactionAdd = this.load(require('./MessageReactionAdd.js'));
this.MessageReactionRemove = this.load(require('./MessageReactionRemove.js'));
this.MessageReactionRemoveAll = this.load(require('./MessageReactionRemoveAll.js'));
this.MessageReactionRemoveEmoji = this.load(require('./MessageReactionRemoveEmoji.js'));
this.MessageUpdate = this.load(require('./MessageUpdate.js'));
this.PresenceUpdate = this.load(require('./PresenceUpdate.js'));
this.StageInstanceCreate = this.load(require('./StageInstanceCreate.js'));
this.StageInstanceDelete = this.load(require('./StageInstanceDelete.js'));
this.StageInstanceUpdate = this.load(require('./StageInstanceUpdate.js'));
this.ThreadCreate = this.load(require('./ThreadCreate.js'));
this.ThreadDelete = this.load(require('./ThreadDelete.js'));
this.ThreadListSync = this.load(require('./ThreadListSync.js'));
this.ThreadMemberUpdate = this.load(require('./ThreadMemberUpdate.js'));
this.ThreadMembersUpdate = this.load(require('./ThreadMembersUpdate.js'));
this.TypingStart = this.load(require('./TypingStart.js'));
this.UserUpdate = this.load(require('./UserUpdate.js'));
this.VoiceStateUpdate = this.load(require('./VoiceStateUpdate.js'));
this.WebhooksUpdate = this.load(require('./WebhooksUpdate.js'));
this.register(require('./ApplicationCommandPermissionsUpdate'));
this.register(require('./AutoModerationActionExecution'));
this.register(require('./AutoModerationRuleCreate'));
this.register(require('./AutoModerationRuleDelete'));
this.register(require('./AutoModerationRuleUpdate'));
this.register(require('./ChannelCreate'));
this.register(require('./ChannelDelete'));
this.register(require('./ChannelUpdate'));
this.register(require('./EntitlementCreate'));
this.register(require('./EntitlementDelete'));
this.register(require('./EntitlementUpdate'));
this.register(require('./GuildAuditLogEntryCreate'));
this.register(require('./GuildBanAdd'));
this.register(require('./GuildBanRemove'));
this.register(require('./GuildChannelsPositionUpdate'));
this.register(require('./GuildDelete'));
this.register(require('./GuildEmojiCreate'));
this.register(require('./GuildEmojiDelete'));
this.register(require('./GuildEmojiUpdate'));
this.register(require('./GuildEmojisUpdate'));
this.register(require('./GuildIntegrationsUpdate'));
this.register(require('./GuildMemberRemove'));
this.register(require('./GuildMemberUpdate'));
this.register(require('./GuildRoleCreate'));
this.register(require('./GuildRoleDelete'));
this.register(require('./GuildRoleUpdate'));
this.register(require('./GuildRolesPositionUpdate'));
this.register(require('./GuildScheduledEventCreate'));
this.register(require('./GuildScheduledEventDelete'));
this.register(require('./GuildScheduledEventUpdate'));
this.register(require('./GuildScheduledEventUserAdd'));
this.register(require('./GuildScheduledEventUserRemove'));
this.register(require('./GuildStickerCreate'));
this.register(require('./GuildStickerDelete'));
this.register(require('./GuildStickerUpdate'));
this.register(require('./GuildStickersUpdate'));
this.register(require('./GuildUpdate'));
this.register(require('./InteractionCreate'));
this.register(require('./InviteCreate'));
this.register(require('./InviteDelete'));
this.register(require('./MessageCreate'));
this.register(require('./MessageDelete'));
this.register(require('./MessageDeleteBulk'));
this.register(require('./MessagePollVoteAdd'));
this.register(require('./MessagePollVoteRemove'));
this.register(require('./MessageReactionAdd'));
this.register(require('./MessageReactionRemove'));
this.register(require('./MessageReactionRemoveAll'));
this.register(require('./MessageReactionRemoveEmoji'));
this.register(require('./MessageUpdate'));
this.register(require('./PresenceUpdate'));
this.register(require('./StageInstanceCreate'));
this.register(require('./StageInstanceDelete'));
this.register(require('./StageInstanceUpdate'));
this.register(require('./ThreadCreate'));
this.register(require('./ThreadDelete'));
this.register(require('./ThreadListSync'));
this.register(require('./ThreadMemberUpdate'));
this.register(require('./ThreadMembersUpdate'));
this.register(require('./TypingStart'));
this.register(require('./UserUpdate'));
this.register(require('./VoiceStateUpdate'));
this.register(require('./WebhooksUpdate'));
}
load(Action) {
return new Action(this.client);
register(Action) {
this[Action.name.replace(/Action$/, '')] = new Action(this.client);
}
}

View File

@@ -1,29 +0,0 @@
'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;

View File

@@ -9,7 +9,6 @@ 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');
@@ -39,9 +38,6 @@ class InteractionCreateAction extends Action {
if (channel && !channel.isTextBased()) return;
InteractionClass = MessageContextMenuCommandInteraction;
break;
case ApplicationCommandType.PrimaryEntryPoint:
InteractionClass = PrimaryEntryPointCommandInteraction;
break;
default:
client.emit(
Events.Debug,

View File

@@ -6,11 +6,7 @@ const Events = require('../../util/Events');
class MessageCreateAction extends Action {
handle(data) {
const client = this.client;
const channel = this.getChannel({
id: data.channel_id,
author: data.author,
...('guild_id' in data && { guild_id: data.guild_id }),
});
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id, author: data.author });
if (channel) {
if (!channel.isTextBased()) return {};

View File

@@ -6,7 +6,7 @@ const Events = require('../../util/Events');
class MessageDeleteAction extends Action {
handle(data) {
const client = this.client;
const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id });
let message;
if (channel) {
if (!channel.isTextBased()) return {};

View File

@@ -5,24 +5,17 @@ const Events = require('../../util/Events');
class MessagePollVoteAddAction extends Action {
handle(data) {
const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id });
if (!channel?.isTextBased()) return false;
const message = this.getMessage(data, channel);
if (!message) return false;
const poll = this.getPoll(data, message, channel);
if (!poll) return false;
const { poll } = message;
const answer = poll.answers.get(data.answer_id);
const answer = poll?.answers.get(data.answer_id);
if (!answer) return false;
const user = this.getUser(data);
if (user) {
answer.voters._add(user);
}
answer.voteCount++;
/**

View File

@@ -5,23 +5,18 @@ const Events = require('../../util/Events');
class MessagePollVoteRemoveAction extends Action {
handle(data) {
const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id });
if (!channel?.isTextBased()) return false;
const message = this.getMessage(data, channel);
if (!message) return false;
const poll = this.getPoll(data, message, channel);
if (!poll) return false;
const { poll } = message;
const answer = poll.answers.get(data.answer_id);
const answer = poll?.answers.get(data.answer_id);
if (!answer) return false;
answer.voters.cache.delete(data.user_id);
if (answer.voteCount > 0) {
answer.voteCount--;
}
answer.voteCount--;
/**
* Emitted whenever a user removes their vote in a poll.

View File

@@ -23,13 +23,7 @@ class MessageReactionAdd extends Action {
if (!user) return false;
// Verify channel
const channel = this.getChannel({
id: data.channel_id,
...('guild_id' in data && { guild_id: data.guild_id }),
user_id: data.user_id,
...this.spreadInjectedData(data),
});
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id, user_id: data.user_id });
if (!channel?.isTextBased()) return false;
// Verify message
@@ -51,7 +45,6 @@ class MessageReactionAdd extends Action {
/**
* Provides additional information about altered reaction
* @typedef {Object} MessageReactionEventDetails
* @property {ReactionType} type The type of the reaction
* @property {boolean} burst Determines whether a super reaction was used
*/
/**
@@ -61,7 +54,7 @@ class MessageReactionAdd extends Action {
* @param {User} user The user that applied the guild or reaction emoji
* @param {MessageReactionEventDetails} details Details of adding the reaction
*/
this.client.emit(Events.MessageReactionAdd, reaction, user, { type: data.type, burst: data.burst });
this.client.emit(Events.MessageReactionAdd, reaction, user, { burst: data.burst });
return { message, reaction, user };
}

View File

@@ -19,11 +19,7 @@ class MessageReactionRemove extends Action {
if (!user) return false;
// Verify channel
const channel = this.getChannel({
id: data.channel_id,
...('guild_id' in data && { guild_id: data.guild_id }),
user_id: data.user_id,
});
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id, user_id: data.user_id });
if (!channel?.isTextBased()) return false;
// Verify message
@@ -41,7 +37,7 @@ class MessageReactionRemove extends Action {
* @param {User} user The user whose emoji or reaction emoji was removed
* @param {MessageReactionEventDetails} details Details of removing the reaction
*/
this.client.emit(Events.MessageReactionRemove, reaction, user, { type: data.type, burst: data.burst });
this.client.emit(Events.MessageReactionRemove, reaction, user, { burst: data.burst });
return { message, reaction, user };
}

View File

@@ -6,7 +6,7 @@ const Events = require('../../util/Events');
class MessageReactionRemoveAll extends Action {
handle(data) {
// Verify channel
const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id });
if (!channel?.isTextBased()) return false;
// Verify message

View File

@@ -5,7 +5,7 @@ const Events = require('../../util/Events');
class MessageReactionRemoveEmoji extends Action {
handle(data) {
const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id });
if (!channel?.isTextBased()) return false;
const message = this.getMessage(data, channel);

View File

@@ -4,7 +4,7 @@ const Action = require('./Action');
class MessageUpdateAction extends Action {
handle(data) {
const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id });
if (channel) {
if (!channel.isTextBased()) return {};

View File

@@ -2,14 +2,11 @@
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 && ('username' in data.user || this.client.options.partials.includes(Partials.User))) {
user = this.client.users._add(data.user);
}
if (!user && data.user.username) user = this.client.users._add(data.user);
if (!user) return;
if (data.user.username) {

View File

@@ -13,7 +13,7 @@ class ThreadListSyncAction extends Action {
if (data.channel_ids) {
for (const id of data.channel_ids) {
const channel = client.channels.cache.get(id);
const channel = client.channels.resolve(id);
if (channel) this.removeStale(channel);
}
} else {

View File

@@ -6,7 +6,7 @@ const Events = require('../../util/Events');
class TypingStart extends Action {
handle(data) {
const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id });
if (!channel) return;
if (!channel.isTextBased()) {

View File

@@ -19,7 +19,6 @@ const Status = require('../../util/Status');
const WebSocketShardEvents = require('../../util/WebSocketShardEvents');
let zlib;
let deprecationEmitted = false;
try {
zlib = require('zlib-sync');
@@ -37,13 +36,10 @@ const BeforeReadyWhitelist = [
const WaitingForGuildEvents = [GatewayDispatchEvents.GuildCreate, GatewayDispatchEvents.GuildDelete];
const UNRECOVERABLE_CLOSE_CODES = [
GatewayCloseCodes.AuthenticationFailed,
GatewayCloseCodes.InvalidShard,
GatewayCloseCodes.ShardingRequired,
GatewayCloseCodes.InvalidAPIVersion,
GatewayCloseCodes.InvalidIntents,
GatewayCloseCodes.DisallowedIntents,
const UNRESUMABLE_CLOSE_CODES = [
CloseCodes.Normal,
GatewayCloseCodes.AlreadyAuthenticated,
GatewayCloseCodes.InvalidSeq,
];
const reasonIsDeprecated = 'the reason property is deprecated, use the code property to determine the reason';
@@ -246,7 +242,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 (UNRECOVERABLE_CLOSE_CODES.includes(code)) {
if (UNRESUMABLE_CLOSE_CODES.includes(code) && this.destroyed) {
shard.status = Status.Disconnected;
/**
* Emitted when a shard's WebSocket disconnects and will no longer reconnect.
@@ -255,7 +251,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 recoverable: ${code} (${GatewayCloseCodes[code] ?? CloseCodes[code]})`], shardId);
this.debug([`Shard not resumable: ${code} (${GatewayCloseCodes[code] ?? CloseCodes[code]})`], shardId);
return;
}
@@ -380,22 +376,6 @@ 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);

View File

@@ -1,24 +0,0 @@
'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);
};

View File

@@ -1,18 +0,0 @@
'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);
};

View File

@@ -1,5 +0,0 @@
'use strict';
module.exports = (client, { d: data }) => {
client.actions.GuildSoundboardSoundDelete.handle(data);
};

View File

@@ -1,20 +0,0 @@
'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);
};

View File

@@ -1,24 +0,0 @@
'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);
};

View File

@@ -1,14 +0,0 @@
'use strict';
const Events = require('../../../util/Events');
module.exports = (client, { d: data }) => {
const subscription = client.application.subscriptions._add(data);
/**
* Emitted whenever a subscription is created.
* @event Client#subscriptionCreate
* @param {Subscription} subscription The subscription that was created
*/
client.emit(Events.SubscriptionCreate, subscription);
};

View File

@@ -1,16 +0,0 @@
'use strict';
const Events = require('../../../util/Events');
module.exports = (client, { d: data }) => {
const subscription = client.application.subscriptions._add(data, false);
client.application.subscriptions.cache.delete(subscription.id);
/**
* Emitted whenever a subscription is deleted.
* @event Client#subscriptionDelete
* @param {Subscription} subscription The subscription that was deleted
*/
client.emit(Events.SubscriptionDelete, subscription);
};

View File

@@ -1,16 +0,0 @@
'use strict';
const Events = require('../../../util/Events');
module.exports = (client, { d: data }) => {
const oldSubscription = client.application.subscriptions.cache.get(data.id)?._clone() ?? null;
const newSubscription = client.application.subscriptions._add(data);
/**
* Emitted whenever a subscription is updated - i.e. when a user's subscription renews.
* @event Client#subscriptionUpdate
* @param {?Subscription} oldSubscription The subscription before the update
* @param {Subscription} newSubscription The subscription after the update
*/
client.emit(Events.SubscriptionUpdate, oldSubscription, newSubscription);
};

View File

@@ -1,16 +0,0 @@
'use strict';
const VoiceChannelEffect = require('../../../structures/VoiceChannelEffect');
const Events = require('../../../util/Events');
module.exports = (client, { d: data }) => {
const guild = client.guilds.cache.get(data.guild_id);
if (!guild) return;
/**
* Emitted when someone sends an effect, such as an emoji reaction, in a voice channel the client is connected to.
* @event Client#voiceChannelEffectSend
* @param {VoiceChannelEffect} voiceChannelEffect The sent voice channel effect
*/
client.emit(Events.VoiceChannelEffectSend, new VoiceChannelEffect(data, guild));
};

View File

@@ -32,10 +32,6 @@ 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')],
['GUILD_SOUNDBOARD_SOUND_CREATE', require('./GUILD_SOUNDBOARD_SOUND_CREATE')],
['GUILD_SOUNDBOARD_SOUND_DELETE', require('./GUILD_SOUNDBOARD_SOUND_DELETE')],
['GUILD_SOUNDBOARD_SOUND_UPDATE', require('./GUILD_SOUNDBOARD_SOUND_UPDATE')],
['GUILD_STICKERS_UPDATE', require('./GUILD_STICKERS_UPDATE')],
['GUILD_UPDATE', require('./GUILD_UPDATE')],
['INTERACTION_CREATE', require('./INTERACTION_CREATE')],
@@ -54,13 +50,9 @@ const handlers = Object.fromEntries([
['PRESENCE_UPDATE', require('./PRESENCE_UPDATE')],
['READY', require('./READY')],
['RESUMED', require('./RESUMED')],
['SOUNDBOARD_SOUNDS', require('./SOUNDBOARD_SOUNDS')],
['STAGE_INSTANCE_CREATE', require('./STAGE_INSTANCE_CREATE')],
['STAGE_INSTANCE_DELETE', require('./STAGE_INSTANCE_DELETE')],
['STAGE_INSTANCE_UPDATE', require('./STAGE_INSTANCE_UPDATE')],
['SUBSCRIPTION_CREATE', require('./SUBSCRIPTION_CREATE')],
['SUBSCRIPTION_DELETE', require('./SUBSCRIPTION_DELETE')],
['SUBSCRIPTION_UPDATE', require('./SUBSCRIPTION_UPDATE')],
['THREAD_CREATE', require('./THREAD_CREATE')],
['THREAD_DELETE', require('./THREAD_DELETE')],
['THREAD_LIST_SYNC', require('./THREAD_LIST_SYNC')],
@@ -69,7 +61,6 @@ const handlers = Object.fromEntries([
['THREAD_UPDATE', require('./THREAD_UPDATE')],
['TYPING_START', require('./TYPING_START')],
['USER_UPDATE', require('./USER_UPDATE')],
['VOICE_CHANNEL_EFFECT_SEND', require('./VOICE_CHANNEL_EFFECT_SEND')],
['VOICE_SERVER_UPDATE', require('./VOICE_SERVER_UPDATE')],
['VOICE_STATE_UPDATE', require('./VOICE_STATE_UPDATE')],
['WEBHOOKS_UPDATE', require('./WEBHOOKS_UPDATE')],

View File

@@ -106,7 +106,6 @@
* @property {'GuildChannelUnowned'} GuildChannelUnowned
* @property {'GuildOwned'} GuildOwned
* @property {'GuildMembersTimeout'} GuildMembersTimeout
* @property {'GuildSoundboardSoundsTimeout'} GuildSoundboardSoundsTimeout
* @property {'GuildUncachedMe'} GuildUncachedMe
* @property {'ChannelNotCached'} ChannelNotCached
* @property {'StageChannelResolve'} StageChannelResolve
@@ -132,8 +131,6 @@
* @property {'MissingManageEmojisAndStickersPermission'} MissingManageEmojisAndStickersPermission
* <warn>This property is deprecated. Use `MissingManageGuildExpressionsPermission` instead.</warn>
*
* @property {'NotGuildSoundboardSound'} NotGuildSoundboardSound
* @property {'NotGuildSticker'} NotGuildSticker
* @property {'ReactionResolveUser'} ReactionResolveUser
@@ -269,7 +266,6 @@ const keys = [
'GuildChannelUnowned',
'GuildOwned',
'GuildMembersTimeout',
'GuildSoundboardSoundsTimeout',
'GuildUncachedMe',
'ChannelNotCached',
'StageChannelResolve',
@@ -294,7 +290,6 @@ const keys = [
'MissingManageGuildExpressionsPermission',
'MissingManageEmojisAndStickersPermission',
'NotGuildSoundboardSound',
'NotGuildSticker',
'ReactionResolveUser',

View File

@@ -91,13 +91,11 @@ 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} ${type === 'group DM' ? 'owner' : 'member'}.`,
[DjsErrorCodes.FetchOwnerId]: type => `Couldn't resolve the ${type} ownerId to fetch the ${type} 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}`,
@@ -119,8 +117,6 @@ 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.",

View File

@@ -29,11 +29,11 @@ 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;
exports.IntentsBitField = require('./util/IntentsBitField');
exports.InviteFlagsBitField = require('./util/InviteFlagsBitField.js').InviteFlagsBitField;
exports.LimitedCollection = require('./util/LimitedCollection');
exports.MessageFlagsBitField = require('./util/MessageFlagsBitField');
exports.Options = require('./util/Options');
@@ -76,18 +76,15 @@ 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');
exports.PermissionOverwriteManager = require('./managers/PermissionOverwriteManager');
exports.PollAnswerVoterManager = require('./managers/PollAnswerVoterManager.js').PollAnswerVoterManager;
exports.PresenceManager = require('./managers/PresenceManager');
exports.ReactionManager = require('./managers/ReactionManager');
exports.ReactionUserManager = require('./managers/ReactionUserManager');
exports.RoleManager = require('./managers/RoleManager');
exports.StageInstanceManager = require('./managers/StageInstanceManager');
exports.SubscriptionManager = require('./managers/SubscriptionManager').SubscriptionManager;
exports.ThreadManager = require('./managers/ThreadManager');
exports.ThreadMemberManager = require('./managers/ThreadMemberManager');
exports.UserManager = require('./managers/UserManager');
@@ -126,15 +123,12 @@ 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');
@@ -152,9 +146,6 @@ exports.GuildScheduledEvent = require('./structures/GuildScheduledEvent').GuildS
exports.GuildTemplate = require('./structures/GuildTemplate');
exports.Integration = require('./structures/Integration');
exports.IntegrationApplication = require('./structures/IntegrationApplication');
exports.InteractionCallback = require('./structures/InteractionCallback');
exports.InteractionCallbackResource = require('./structures/InteractionCallbackResource');
exports.InteractionCallbackResponse = require('./structures/InteractionCallbackResponse');
exports.BaseInteraction = require('./structures/BaseInteraction');
exports.InteractionCollector = require('./structures/InteractionCollector');
exports.InteractionResponse = require('./structures/InteractionResponse');
@@ -167,8 +158,6 @@ 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');
@@ -183,13 +172,11 @@ 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');
@@ -211,30 +198,23 @@ 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;
exports.Subscription = require('./structures/Subscription').Subscription;
exports.Sticker = require('./structures/Sticker').Sticker;
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');
exports.VoiceChannel = require('./structures/VoiceChannel');
exports.VoiceRegion = require('./structures/VoiceRegion');
exports.VoiceState = require('./structures/VoiceState');

View File

@@ -82,7 +82,7 @@ class ApplicationCommandManager extends CachedManager {
* Options used to fetch Application Commands from Discord
* @typedef {BaseFetchOptions} FetchApplicationCommandOptions
* @property {Snowflake} [guildId] The guild's id to fetch commands for, for when the guild is not cached
* @property {Locale} [locale] The locale to use when fetching this command
* @property {LocaleString} [locale] The locale to use when fetching this command
* @property {boolean} [withLocalizations] Whether to fetch all localization data
*/
@@ -261,7 +261,6 @@ class ApplicationCommandManager extends CachedManager {
dm_permission: command.dmPermission ?? command.dm_permission,
integration_types: command.integrationTypes ?? command.integration_types,
contexts: command.contexts,
handler: command.handler,
};
}
}

View File

@@ -65,12 +65,12 @@ class ApplicationEmojiManager extends CachedManager {
* @returns {Promise<ApplicationEmoji|Collection<Snowflake, ApplicationEmoji>>}
* @example
* // Fetch all emojis from the application
* application.emojis.fetch()
* message.application.emojis.fetch()
* .then(emojis => console.log(`There are ${emojis.size} emojis.`))
* .catch(console.error);
* @example
* // Fetch a single emoji
* application.emojis.fetch('222078108977594368')
* message.application.emojis.fetch('222078108977594368')
* .then(emoji => console.log(`The emoji name is: ${emoji.name}`))
* .catch(console.error);
*/

View File

@@ -1,7 +1,6 @@
'use strict';
const CachedManager = require('./CachedManager');
const ApplicationEmoji = require('../structures/ApplicationEmoji');
const GuildEmoji = require('../structures/GuildEmoji');
const ReactionEmoji = require('../structures/ReactionEmoji');
const { parseEmoji } = require('../util/Util');
@@ -26,8 +25,7 @@ class BaseGuildEmojiManager extends CachedManager {
* * A Snowflake
* * A GuildEmoji object
* * A ReactionEmoji object
* * An ApplicationEmoji object
* @typedef {Snowflake|GuildEmoji|ReactionEmoji|ApplicationEmoji} EmojiResolvable
* @typedef {Snowflake|GuildEmoji|ReactionEmoji} EmojiResolvable
*/
/**
@@ -36,8 +34,7 @@ class BaseGuildEmojiManager extends CachedManager {
* @returns {?GuildEmoji}
*/
resolve(emoji) {
if (emoji instanceof ReactionEmoji) return this.cache.get(emoji.id) ?? null;
if (emoji instanceof ApplicationEmoji) return this.cache.get(emoji.id) ?? null;
if (emoji instanceof ReactionEmoji) return super.resolve(emoji.id);
return super.resolve(emoji);
}
@@ -48,7 +45,6 @@ class BaseGuildEmojiManager extends CachedManager {
*/
resolveId(emoji) {
if (emoji instanceof ReactionEmoji) return emoji.id;
if (emoji instanceof ApplicationEmoji) return emoji.id;
return super.resolveId(emoji);
}
@@ -69,7 +65,6 @@ class BaseGuildEmojiManager extends CachedManager {
const emojiResolvable = this.resolve(emoji);
if (emojiResolvable) return emojiResolvable.identifier;
if (emoji instanceof ReactionEmoji) return emoji.identifier;
if (emoji instanceof ApplicationEmoji) return emoji.identifier;
if (typeof emoji === 'string') {
const res = parseEmoji(emoji);
if (res?.name.length) {

View File

@@ -69,13 +69,6 @@ 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);
}
}
}
/**

View File

@@ -37,12 +37,6 @@ class EntitlementManager extends CachedManager {
* @typedef {SKU|Snowflake} SKUResolvable
*/
/**
* Options used to fetch an entitlement
* @typedef {BaseFetchOptions} FetchEntitlementOptions
* @property {EntitlementResolvable} entitlement The entitlement to fetch
*/
/**
* Options used to fetch entitlements
* @typedef {Object} FetchEntitlementsOptions
@@ -51,7 +45,6 @@ class EntitlementManager extends CachedManager {
* @property {UserResolvable} [user] The user to fetch entitlements for
* @property {SKUResolvable[]} [skus] The SKUs to fetch entitlements for
* @property {boolean} [excludeEnded] Whether to exclude ended entitlements
* @property {boolean} [excludeDeleted] Whether to exclude deleted entitlements
* @property {boolean} [cache=true] Whether to cache the fetched entitlements
* @property {Snowflake} [before] Consider only entitlements before this entitlement id
* @property {Snowflake} [after] Consider only entitlements after this entitlement id
@@ -60,49 +53,21 @@ class EntitlementManager extends CachedManager {
/**
* Fetches entitlements for this application
* @param {EntitlementResolvable|FetchEntitlementOptions|FetchEntitlementsOptions} [options]
* Options for fetching the entitlements
* @returns {Promise<Entitlement|Collection<Snowflake, Entitlement>>}
* @param {FetchEntitlementsOptions} [options={}] Options for fetching the entitlements
* @returns {Promise<Collection<Snowflake, Entitlement>>}
*/
async fetch(options) {
if (!options) return this._fetchMany(options);
const { entitlement, cache, force } = options;
const resolvedEntitlement = this.resolveId(entitlement ?? options);
if (resolvedEntitlement) {
return this._fetchSingle({ entitlement: resolvedEntitlement, cache, force });
}
return this._fetchMany(options);
}
async _fetchSingle({ entitlement, cache, force = false }) {
if (!force) {
const existing = this.cache.get(entitlement);
if (existing) {
return existing;
}
}
const data = await this.client.rest.get(Routes.entitlement(this.client.application.id, entitlement));
return this._add(data, cache);
}
async _fetchMany({ limit, guild, user, skus, excludeEnded, excludeDeleted, cache, before, after } = {}) {
async fetch({ limit, guild, user, skus, excludeEnded, cache = true, before, after } = {}) {
const query = makeURLSearchParams({
limit,
guild_id: guild && this.client.guilds.resolveId(guild),
user_id: user && this.client.users.resolveId(user),
sku_ids: skus?.map(sku => resolveSKUId(sku)).join(','),
exclude_ended: excludeEnded,
exclude_deleted: excludeDeleted,
before,
after,
});
const entitlements = await this.client.rest.get(Routes.entitlements(this.client.application.id), { query });
return entitlements.reduce(
(coll, entitlement) => coll.set(entitlement.id, this._add(entitlement, cache)),
new Collection(),

View File

@@ -97,14 +97,14 @@ class GuildBanManager extends CachedManager {
* .then(console.log)
* .catch(console.error);
*/
async fetch(options) {
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) {
throw new DiscordjsError(ErrorCodes.FetchBanResolveId);
return Promise.reject(new DiscordjsError(ErrorCodes.FetchBanResolveId));
}
return this._fetchMany(options);
@@ -175,7 +175,7 @@ class GuildBanManager extends CachedManager {
reason: options.reason,
});
if (user instanceof GuildMember) return user;
const _user = this.client.users.cache.get(id);
const _user = this.client.users.resolve(id);
if (_user) {
return this.guild.members.resolve(_user) ?? _user;
}

View File

@@ -84,7 +84,7 @@ class GuildChannelManager extends CachedManager {
* @returns {?(GuildChannel|ThreadChannel)}
*/
resolve(channel) {
if (channel instanceof ThreadChannel) return this.cache.get(channel.id) ?? null;
if (channel instanceof ThreadChannel) return super.resolve(channel.id);
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');
const resolvedImage = await resolveImage(avatar);
if (typeof avatar === 'string' && !avatar.startsWith('data:')) {
avatar = await resolveImage(avatar);
}
const data = await this.client.rest.post(Routes.channelWebhooks(id), {
body: {
name,
avatar: resolvedImage,
avatar,
},
reason,
});
@@ -287,7 +287,7 @@ class GuildChannelManager extends CachedManager {
const resolvedChannel = this.resolve(channel);
if (!resolvedChannel) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable');
const parentId = options.parent && this.client.channels.resolveId(options.parent);
const parent = options.parent && this.client.channels.resolveId(options.parent);
if (options.position !== undefined) {
await this.setPosition(resolvedChannel, options.position, { position: options.position, reason: options.reason });
@@ -298,8 +298,8 @@ class GuildChannelManager extends CachedManager {
);
if (options.lockPermissions) {
if (parentId) {
const newParent = this.cache.get(parentId);
if (parent) {
const newParent = this.guild.channels.resolve(parent);
if (newParent?.type === ChannelType.GuildCategory) {
permission_overwrites = newParent.permissionOverwrites.cache.map(overwrite =>
PermissionOverwrites.resolve(overwrite, this.guild),
@@ -322,7 +322,7 @@ class GuildChannelManager extends CachedManager {
user_limit: options.userLimit,
rtc_region: options.rtcRegion,
video_quality_mode: options.videoQualityMode,
parent_id: parentId,
parent_id: parent,
lock_permissions: options.lockPermissions,
rate_limit_per_user: options.rateLimitPerUser,
default_auto_archive_duration: options.defaultAutoArchiveDuration,

View File

@@ -39,14 +39,14 @@ class GuildEmojiRoleManager extends DataManager {
* @param {RoleResolvable|RoleResolvable[]|Collection<Snowflake, Role>} roleOrRoles The role or roles to add
* @returns {Promise<GuildEmoji>}
*/
async add(roleOrRoles) {
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) {
throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'roles', role);
return Promise.reject(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>}
*/
async remove(roleOrRoles) {
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) {
throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'roles', role);
return Promise.reject(new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'roles', role));
}
resolvedRoleIds.push(roleId);
}

View File

@@ -121,22 +121,22 @@ class GuildInviteManager extends CachedManager {
* .then(console.log)
* .catch(console.error);
*/
async fetch(options) {
fetch(options) {
if (!options) return this._fetchMany();
if (typeof options === 'string') {
const code = resolveInviteCode(options);
if (!code) throw new DiscordjsError(ErrorCodes.InviteResolveCode);
if (!code) return Promise.reject(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) throw new DiscordjsError(ErrorCodes.GuildChannelResolve);
if (!id) return Promise.reject(new DiscordjsError(ErrorCodes.GuildChannelResolve));
return this._fetchChannelMany(id, options.cache);
}
if ('cache' in options) return this._fetchMany(options.cache);
throw new DiscordjsError(ErrorCodes.InviteResolveCode);
return Promise.reject(new DiscordjsError(ErrorCodes.InviteResolveCode));
}
return this._fetchSingle({
...options,

View File

@@ -4,9 +4,8 @@ const process = require('node:process');
const { setTimeout, clearTimeout } = require('node:timers');
const { Collection } = require('@discordjs/collection');
const { makeURLSearchParams } = require('@discordjs/rest');
const { GatewayOpcodes, Routes, RouteBases } = require('discord-api-types/v10');
const { 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');
@@ -19,7 +18,6 @@ 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;
@@ -163,7 +161,6 @@ class GuildManager extends CachedManager {
* Creates a guild.
* <warn>This is only available to bots in fewer than 10 guilds.</warn>
* @param {GuildCreateOptions} options Options for creating the guild
* @deprecated API related to guild ownership may no longer be used.
* @returns {Promise<Guild>} The guild that was created
*/
async create({
@@ -284,112 +281,6 @@ 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

View File

@@ -54,8 +54,8 @@ class GuildMemberManager extends CachedManager {
resolve(member) {
const memberResolvable = super.resolve(member);
if (memberResolvable) return memberResolvable;
const userId = this.client.users.resolveId(member);
if (userId) return this.cache.get(userId) ?? null;
const userResolvable = this.client.users.resolveId(member);
if (userResolvable) return super.resolve(userResolvable);
return null;
}
@@ -67,8 +67,8 @@ class GuildMemberManager extends CachedManager {
resolveId(member) {
const memberResolvable = super.resolveId(member);
if (memberResolvable) return memberResolvable;
const userId = this.client.users.resolveId(member);
return this.cache.has(userId) ? userId : null;
const userResolvable = this.client.users.resolveId(member);
return this.cache.has(userResolvable) ? userResolvable : null;
}
/**
@@ -144,7 +144,7 @@ class GuildMemberManager extends CachedManager {
*/
get me() {
return (
this.cache.get(this.client.user.id) ??
this.resolve(this.client.user.id) ??
(this.client.options.partials.includes(Partials.GuildMember)
? this._add({ user: { id: this.client.user.id } }, true)
: null)
@@ -223,7 +223,7 @@ class GuildMemberManager extends CachedManager {
return this._add(data, cache);
}
async _fetchMany({
_fetchMany({
limit = 0,
withPresences: presences,
users,
@@ -231,7 +231,7 @@ class GuildMemberManager extends CachedManager {
time = 120e3,
nonce = DiscordSnowflake.generate().toString(),
} = {}) {
if (nonce.length > 32) throw new DiscordjsRangeError(ErrorCodes.MemberFetchNonceLength);
if (nonce.length > 32) return Promise.reject(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) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'user', 'UserResolvable');
if (!id) return Promise.reject(new DiscordjsTypeError(ErrorCodes.InvalidType, 'user', 'UserResolvable'));
await this.client.rest.delete(Routes.guildMember(this.guild.id, id), { reason });
@@ -535,7 +535,7 @@ class GuildMemberManager extends CachedManager {
*/
async addRole(options) {
const { user, role, reason } = options;
const userId = this.resolveId(user);
const userId = this.guild.members.resolveId(user);
const roleId = this.guild.roles.resolveId(role);
await this.client.rest.put(Routes.guildMemberRole(this.guild.id, userId, roleId), { reason });
@@ -549,7 +549,7 @@ class GuildMemberManager extends CachedManager {
*/
async removeRole(options) {
const { user, role, reason } = options;
const userId = this.resolveId(user);
const userId = this.guild.members.resolveId(user);
const roleId = this.guild.roles.resolveId(role);
await this.client.rest.delete(Routes.guildMemberRole(this.guild.id, userId, roleId), { reason });

View File

@@ -65,7 +65,7 @@ class GuildMemberRoleManager extends DataManager {
* @readonly
*/
get color() {
const coloredRoles = this.cache.filter(role => role.colors.primaryColor);
const coloredRoles = this.cache.filter(role => role.color);
if (!coloredRoles.size) return null;
return coloredRoles.reduce((prev, role) => (role.comparePositionTo(prev) > 0 ? role : prev));
}
@@ -101,8 +101,6 @@ class GuildMemberRoleManager extends DataManager {
/**
* Adds a role (or multiple roles) to the member.
*
* <info>Uses the idempotent PUT route for singular roles, otherwise PATCHes the underlying guild member</info>
* @param {RoleResolvable|RoleResolvable[]|Collection<Snowflake, Role>} roleOrRoles The role or roles to add
* @param {string} [reason] Reason for adding the role(s)
* @returns {Promise<GuildMember>}
@@ -140,8 +138,6 @@ class GuildMemberRoleManager extends DataManager {
/**
* Removes a role (or multiple roles) from the member.
*
* <info>Uses the idempotent DELETE route for singular roles, otherwise PATCHes the underlying guild member</info>
* @param {RoleResolvable|RoleResolvable[]|Collection<Snowflake, Role>} roleOrRoles The role or roles to remove
* @param {string} [reason] Reason for removing the role(s)
* @returns {Promise<GuildMember>}

View File

@@ -7,7 +7,6 @@ const CachedManager = require('./CachedManager');
const { DiscordjsTypeError, DiscordjsError, ErrorCodes } = require('../errors');
const { GuildScheduledEvent } = require('../structures/GuildScheduledEvent');
const { resolveImage } = require('../util/DataResolver');
const { _transformGuildScheduledEventRecurrenceRule } = require('../util/Transformers');
/**
* Manages API methods for GuildScheduledEvents and stores their cache.
@@ -37,18 +36,6 @@ class GuildScheduledEventManager extends CachedManager {
* @typedef {Snowflake|GuildScheduledEvent} GuildScheduledEventResolvable
*/
/**
* 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 {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
*/
/**
* Options used to create a guild scheduled event.
* @typedef {Object} GuildScheduledEventCreateOptions
@@ -67,8 +54,6 @@ class GuildScheduledEventManager extends CachedManager {
* <warn>This is required if `entityType` is {@link GuildScheduledEventEntityType.External}</warn>
* @property {?(BufferResolvable|Base64Resolvable)} [image] The cover image of the guild scheduled event
* @property {string} [reason] The reason for creating the guild scheduled event
* @property {GuildScheduledEventRecurrenceRuleOptions} [recurrenceRule]
* The recurrence rule of the guild scheduled event
*/
/**
@@ -96,7 +81,6 @@ class GuildScheduledEventManager extends CachedManager {
entityMetadata,
reason,
image,
recurrenceRule,
} = options;
let entity_metadata, channel_id;
@@ -120,7 +104,6 @@ class GuildScheduledEventManager extends CachedManager {
entity_type: entityType,
entity_metadata,
image: image && (await resolveImage(image)),
recurrence_rule: recurrenceRule && _transformGuildScheduledEventRecurrenceRule(recurrenceRule),
},
reason,
});
@@ -170,7 +153,10 @@ class GuildScheduledEventManager extends CachedManager {
return data.reduce(
(coll, rawGuildScheduledEventData) =>
coll.set(rawGuildScheduledEventData.id, this._add(rawGuildScheduledEventData, options.cache)),
coll.set(
rawGuildScheduledEventData.id,
this.guild.scheduledEvents._add(rawGuildScheduledEventData, options.cache),
),
new Collection(),
);
}
@@ -192,8 +178,6 @@ class GuildScheduledEventManager extends CachedManager {
* {@link GuildScheduledEventEntityType.External}</warn>
* @property {?(BufferResolvable|Base64Resolvable)} [image] The cover image of the guild scheduled event
* @property {string} [reason] The reason for editing the guild scheduled event
* @property {?GuildScheduledEventRecurrenceRuleOptions} [recurrenceRule]
* The recurrence rule of the guild scheduled event
*/
/**
@@ -219,7 +203,6 @@ class GuildScheduledEventManager extends CachedManager {
entityMetadata,
reason,
image,
recurrenceRule,
} = options;
let entity_metadata;
@@ -241,7 +224,6 @@ class GuildScheduledEventManager extends CachedManager {
status,
image: image && (await resolveImage(image)),
entity_metadata,
recurrence_rule: recurrenceRule && _transformGuildScheduledEventRecurrenceRule(recurrenceRule),
},
reason,
});

View File

@@ -1,214 +0,0 @@
'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;

View File

@@ -1,6 +1,5 @@
'use strict';
const process = require('node:process');
const { Collection } = require('@discordjs/collection');
const { makeURLSearchParams } = require('@discordjs/rest');
const { Routes } = require('discord-api-types/v10');
@@ -11,8 +10,6 @@ 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}
@@ -119,83 +116,19 @@ 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));
@@ -286,7 +219,7 @@ class MessageManager extends CachedManager {
message = this.resolveId(message);
if (!message) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable');
await this.client.rest.put(Routes.channelMessagesPin(this.channel.id, message), { reason });
await this.client.rest.put(Routes.channelPin(this.channel.id, message), { reason });
}
/**
@@ -299,7 +232,7 @@ class MessageManager extends CachedManager {
message = this.resolveId(message);
if (!message) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable');
await this.client.rest.delete(Routes.channelMessagesPin(this.channel.id, message), { reason });
await this.client.rest.delete(Routes.channelPin(this.channel.id, message), { reason });
}
/**

View File

@@ -62,13 +62,15 @@ class PermissionOverwriteManager extends CachedManager {
* },
* ], 'Needed to change permissions');
*/
async set(overwrites, reason) {
set(overwrites, reason) {
if (!Array.isArray(overwrites) && !(overwrites instanceof Collection)) {
throw new DiscordjsTypeError(
ErrorCodes.InvalidType,
'overwrites',
'Array or Collection of Permission Overwrites',
true,
return Promise.reject(
new DiscordjsTypeError(
ErrorCodes.InvalidType,
'overwrites',
'Array or Collection of Permission Overwrites',
true,
),
);
}
return this.channel.edit({ permissionOverwrites: overwrites, reason });

View File

@@ -1,50 +0,0 @@
'use strict';
const { Collection } = require('@discordjs/collection');
const { makeURLSearchParams } = require('@discordjs/rest');
const { Routes } = require('discord-api-types/v10');
const CachedManager = require('./CachedManager.js');
const User = require('../structures/User.js');
/**
* Manages API methods for users who voted on a poll and stores their cache.
* @extends {CachedManager}
*/
class PollAnswerVoterManager extends CachedManager {
constructor(answer) {
super(answer.client, User);
/**
* The poll answer that this manager belongs to
* @type {PollAnswer}
*/
this.answer = answer;
}
/**
* The cache of this manager
* @type {Collection<Snowflake, User>}
* @name PollAnswerVoterManager#cache
*/
/**
* Fetches the users that voted on this poll answer. Resolves with a collection of users, mapped by their ids.
* @param {BaseFetchPollAnswerVotersOptions} [options={}] Options for fetching the users
* @returns {Promise<Collection<Snowflake, User>>}
*/
async fetch({ after, limit } = {}) {
const poll = this.answer.poll;
const query = makeURLSearchParams({ limit, after });
const data = await this.client.rest.get(Routes.pollAnswerVoters(poll.channelId, poll.messageId, this.answer.id), {
query,
});
return data.users.reduce((coll, rawUser) => {
const user = this.client.users._add(rawUser);
this.cache.set(user.id, user);
return coll.set(user.id, user);
}, new Collection());
}
}
exports.PollAnswerVoterManager = PollAnswerVoterManager;

Some files were not shown because too many files have changed in this diff Show More