mirror of
https://github.com/discordjs/discord.js.git
synced 2026-05-28 06:20:10 +00:00
Compare commits
105 Commits
@discordjs
...
14.18.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
595bded8a5 | ||
|
|
c74c632cdb | ||
|
|
fc003050de | ||
|
|
8702978057 | ||
|
|
c2b18d6d8b | ||
|
|
519aa3abe8 | ||
|
|
89c076c89e | ||
|
|
f224a07381 | ||
|
|
8e1e1be0c2 | ||
|
|
193a5e9e20 | ||
|
|
73c6bc2c36 | ||
|
|
b7f1ebc334 | ||
|
|
92aea94411 | ||
|
|
41dee5177d | ||
|
|
bbde371324 | ||
|
|
66b971899a | ||
|
|
43235d43fe | ||
|
|
31df3d21cd | ||
|
|
2663d76709 | ||
|
|
44a1e85847 | ||
|
|
d2e1924fa6 | ||
|
|
68dd260dee | ||
|
|
5e66f85f55 | ||
|
|
46060419a9 | ||
|
|
7c1b73cc69 | ||
|
|
95db597fc8 | ||
|
|
0047a49b73 | ||
|
|
32dff01f29 | ||
|
|
efa50fc3fa | ||
|
|
aa61c20ffd | ||
|
|
d48136bee1 | ||
|
|
46bf8f0146 | ||
|
|
7280d4e82e | ||
|
|
bd2914cc98 | ||
|
|
77804cfd55 | ||
|
|
8fea3ed978 | ||
|
|
05c63cd9a1 | ||
|
|
8d69b24b5c | ||
|
|
9baee4b2ce | ||
|
|
c986a99104 | ||
|
|
2b9e4cf9d0 | ||
|
|
1af2f4ed0e | ||
|
|
3fbfe9f1ae | ||
|
|
b901ff7c4c | ||
|
|
5f8915f6d1 | ||
|
|
ff42d7af72 | ||
|
|
0fdbabea98 | ||
|
|
e9944b3d2d | ||
|
|
2b9833cd36 | ||
|
|
7b2a2e3a15 | ||
|
|
6087088579 | ||
|
|
622acbcbf0 | ||
|
|
b2754d4a0e | ||
|
|
53cbb0e36d | ||
|
|
7ce6f2fc8a | ||
|
|
76042f0538 | ||
|
|
dedaa5d657 | ||
|
|
ed00a10e1f | ||
|
|
ae1deac2bf | ||
|
|
a367e2c8c9 | ||
|
|
7678f1176a | ||
|
|
4cca33d9b0 | ||
|
|
388783d7dd | ||
|
|
bda31284bf | ||
|
|
76968b4bc1 | ||
|
|
34343c6afa | ||
|
|
56c9396b71 | ||
|
|
21c283f964 | ||
|
|
13471fa1b7 | ||
|
|
b1ded63e42 | ||
|
|
565fc0192a | ||
|
|
33533b7284 | ||
|
|
be38f57926 | ||
|
|
f79ba52c7a | ||
|
|
72e0c99454 | ||
|
|
3d06c9d872 | ||
|
|
831aafa733 | ||
|
|
5faf074c14 | ||
|
|
297e959f48 | ||
|
|
1fc87a9698 | ||
|
|
366f7174d0 | ||
|
|
97c3237a70 | ||
|
|
c12217829b | ||
|
|
0873f9a4c3 | ||
|
|
6c77fee41b | ||
|
|
cda8d88ad5 | ||
|
|
665bf1486a | ||
|
|
99136d6be8 | ||
|
|
896dc8b21e | ||
|
|
651f2d036a | ||
|
|
2adee06b6e | ||
|
|
495bc60345 | ||
|
|
d9d578391a | ||
|
|
3c74aa2049 | ||
|
|
799fa54fa4 | ||
|
|
8a74f144ac | ||
|
|
dea68400a3 | ||
|
|
c13f18e90e | ||
|
|
aff772c7aa | ||
|
|
4594896b54 | ||
|
|
a11ff75631 | ||
|
|
9257a09abb | ||
|
|
4810f7c863 | ||
|
|
18ce10a9af | ||
|
|
ed1c1737df |
@@ -9,7 +9,9 @@
|
|||||||
<a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/v/discord.js.svg?maxAge=3600" alt="npm version" /></a>
|
<a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/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://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/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Tests status" /></a>
|
||||||
<a href="https://codecov.io/gh/discordjs/discord.js" ><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2" alt="Code coverage" /></a>
|
<a href="https://github.com/discordjs/discord.js/commits/main"><img src="https://img.shields.io/github/last-commit/discordjs/discord.js.svg?logo=github&logoColor=ffffff" alt="Last commit." /></a>
|
||||||
|
<a href="https://github.com/discordjs/discord.js/graphs/contributors"><img src="https://img.shields.io/github/contributors/discordjs/discord.js.svg?maxAge=3600&logo=github&logoColor=fff&color=00c7be" alt="contributors" /></a>
|
||||||
|
<a href="https://codecov.io/gh/discordjs/discord.js"><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2" alt="Code coverage" /></a>
|
||||||
</p>
|
</p>
|
||||||
<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>
|
<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>
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export async function ParameterNode({
|
|||||||
{description ? <Badges node={parameter} /> : null}
|
{description ? <Badges node={parameter} /> : null}
|
||||||
{parameter.name}
|
{parameter.name}
|
||||||
{parameter.isOptional ? '?' : ''}: <ExcerptNode node={parameter.typeExcerpt} version={version} />
|
{parameter.isOptional ? '?' : ''}: <ExcerptNode node={parameter.typeExcerpt} version={version} />
|
||||||
|
{parameter.defaultValue ? ` = ${parameter.defaultValue}` : ''}
|
||||||
</span>
|
</span>
|
||||||
{description && parameter.description?.length ? (
|
{description && parameter.description?.length ? (
|
||||||
<div className="mt-4 pl-4">
|
<div className="mt-4 pl-4">
|
||||||
|
|||||||
@@ -51,7 +51,13 @@ export async function PropertyNode({
|
|||||||
<LinkIcon aria-hidden size={16} />
|
<LinkIcon aria-hidden size={16} />
|
||||||
</Link>
|
</Link>
|
||||||
{property.displayName}
|
{property.displayName}
|
||||||
{property.isOptional ? '?' : ''} : <ExcerptNode node={property.typeExcerpt} version={version} />
|
{property.isOptional ? '?' : ''} : <ExcerptNode node={property.typeExcerpt} version={version} />{' '}
|
||||||
|
{property.summary?.defaultValueBlock.length
|
||||||
|
? `= ${property.summary.defaultValueBlock.reduce(
|
||||||
|
(acc: string, def: { kind: string; text: string }) => `${acc}${def.text}`,
|
||||||
|
'',
|
||||||
|
)}`
|
||||||
|
: ''}
|
||||||
</span>
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export async function fetchDependencies({
|
|||||||
|
|
||||||
return Object.entries<string>(parsedDependencies)
|
return Object.entries<string>(parsedDependencies)
|
||||||
.filter(([key]) => key.startsWith('@discordjs/') && !key.includes('api-extractor'))
|
.filter(([key]) => key.startsWith('@discordjs/') && !key.includes('api-extractor'))
|
||||||
.map(([key, value]) => `${key.replace('@discordjs/', '').replaceAll('.', '-')}-${value.replaceAll('.', '-')}`);
|
.map(([key, value]) => `${key.replace('@discordjs/', '').replaceAll('.', '-')}-${sanitizeVersion(value)}`);
|
||||||
} catch {
|
} catch {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -36,8 +36,12 @@ export async function fetchDependencies({
|
|||||||
|
|
||||||
return Object.entries<string>(parsedDependencies)
|
return Object.entries<string>(parsedDependencies)
|
||||||
.filter(([key]) => key.startsWith('@discordjs/') && !key.includes('api-extractor'))
|
.filter(([key]) => key.startsWith('@discordjs/') && !key.includes('api-extractor'))
|
||||||
.map(([key, value]) => `${key.replace('@discordjs/', '').replaceAll('.', '-')}-${value.replaceAll('.', '-')}`);
|
.map(([key, value]) => `${key.replace('@discordjs/', '').replaceAll('.', '-')}-${sanitizeVersion(value)}`);
|
||||||
} catch {
|
} catch {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sanitizeVersion(version: string) {
|
||||||
|
return version.replaceAll('.', '-').replace(/^[\^~]/, '');
|
||||||
|
}
|
||||||
|
|||||||
14
package.json
14
package.json
@@ -6,19 +6,19 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "turbo run build --concurrency=4",
|
"build": "turbo run build --concurrency=4",
|
||||||
"build:affected": "turbo run build --filter=...[origin/main] --concurrency=4",
|
"build:affected": "turbo run build --filter=...[origin/v14] --concurrency=4",
|
||||||
"build:apps": "turbo run build:local --filter=...{apps/*} --concurrency=4",
|
"build:apps": "turbo run build:local --filter=...{apps/*} --concurrency=4",
|
||||||
"build:apps:affected": "turbo run build:local --filter=...{apps/*}[origin/main] --concurrency=4",
|
"build:apps:affected": "turbo run build:local --filter=...{apps/*}[origin/v14] --concurrency=4",
|
||||||
"test": "turbo run test --concurrency=4",
|
"test": "turbo run test --concurrency=4",
|
||||||
"test:affected": "turbo run test --filter=...[origin/main] --concurrency=4",
|
"test:affected": "turbo run test --filter=...[origin/v14] --concurrency=4",
|
||||||
"lint": "turbo run lint --concurrency=4",
|
"lint": "turbo run lint --concurrency=4",
|
||||||
"lint:affected": "turbo run lint --filter=...[origin/main] --concurrency=4",
|
"lint:affected": "turbo run lint --filter=...[origin/v14] --concurrency=4",
|
||||||
"format": "turbo run format --concurrency=4",
|
"format": "turbo run format --concurrency=4",
|
||||||
"format:affected": "turbo run format --filter=...[origin/main] --concurrency=4",
|
"format:affected": "turbo run format --filter=...[origin/v14] --concurrency=4",
|
||||||
"fmt": "turbo run format --concurrency=4",
|
"fmt": "turbo run format --concurrency=4",
|
||||||
"fmt:affected": "turbo run format --filter=...[origin/main] --concurrency=4",
|
"fmt:affected": "turbo run format --filter=...[origin/v14] --concurrency=4",
|
||||||
"docs": "turbo run docs --concurrency=4",
|
"docs": "turbo run docs --concurrency=4",
|
||||||
"docs:affected": "turbo run docs --filter=...[origin/main] --concurrency=4",
|
"docs:affected": "turbo run docs --filter=...[origin/v14] --concurrency=4",
|
||||||
"prepare": "is-ci || husky",
|
"prepare": "is-ci || husky",
|
||||||
"update": "pnpm --recursive update --interactive",
|
"update": "pnpm --recursive update --interactive",
|
||||||
"update:latest": "pnpm --recursive update --interactive --latest",
|
"update:latest": "pnpm --recursive update --interactive --latest",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import type { IExcerptTokenRange } from './Excerpt.js';
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface IApiParameterOptions {
|
export interface IApiParameterOptions {
|
||||||
|
defaultValue: string | undefined;
|
||||||
isOptional: boolean;
|
isOptional: boolean;
|
||||||
isRest: boolean;
|
isRest: boolean;
|
||||||
parameterName: string;
|
parameterName: string;
|
||||||
@@ -124,6 +125,7 @@ export function ApiParameterListMixin<TBaseClass extends IApiItemConstructor>(
|
|||||||
isOptional: Boolean(parameterOptions.isOptional),
|
isOptional: Boolean(parameterOptions.isOptional),
|
||||||
isRest: Boolean(parameterOptions.isRest),
|
isRest: Boolean(parameterOptions.isRest),
|
||||||
parent: this,
|
parent: this,
|
||||||
|
defaultValue: parameterOptions.defaultValue,
|
||||||
});
|
});
|
||||||
|
|
||||||
this[_parameters].push(parameter);
|
this[_parameters].push(parameter);
|
||||||
@@ -171,6 +173,7 @@ export function ApiParameterListMixin<TBaseClass extends IApiItemConstructor>(
|
|||||||
parameterTypeTokenRange: parameter.parameterTypeExcerpt.tokenRange,
|
parameterTypeTokenRange: parameter.parameterTypeExcerpt.tokenRange,
|
||||||
isOptional: parameter.isOptional,
|
isOptional: parameter.isOptional,
|
||||||
isRest: parameter.isRest,
|
isRest: parameter.isRest,
|
||||||
|
defaultValue: parameter.defaultValue,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ const MinifyJSONMapping = {
|
|||||||
constraintTokenRange: 'ctr',
|
constraintTokenRange: 'ctr',
|
||||||
dependencies: 'dp',
|
dependencies: 'dp',
|
||||||
defaultTypeTokenRange: 'dtr',
|
defaultTypeTokenRange: 'dtr',
|
||||||
|
defaultValue: 'dv',
|
||||||
docComment: 'd',
|
docComment: 'd',
|
||||||
endIndex: 'en',
|
endIndex: 'en',
|
||||||
excerptTokens: 'ex',
|
excerptTokens: 'ex',
|
||||||
|
|||||||
@@ -262,6 +262,7 @@ function mapParam(
|
|||||||
startIndex: 1 + index + paramTokens.slice(0, index).reduce((akk, num) => akk + num, 0),
|
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),
|
endIndex: 1 + index + paramTokens.slice(0, index + 1).reduce((akk, num) => akk + num, 0),
|
||||||
},
|
},
|
||||||
|
defaultValue: param.default,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import type { Excerpt } from '../mixins/Excerpt.js';
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface IParameterOptions {
|
export interface IParameterOptions {
|
||||||
|
defaultValue: string | undefined;
|
||||||
isOptional: boolean;
|
isOptional: boolean;
|
||||||
isRest: boolean;
|
isRest: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -56,6 +57,11 @@ export class Parameter {
|
|||||||
*/
|
*/
|
||||||
public isRest: boolean;
|
public isRest: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default value for this parameter if optional
|
||||||
|
*/
|
||||||
|
public defaultValue: string | undefined;
|
||||||
|
|
||||||
private readonly _parent: ApiParameterListMixin;
|
private readonly _parent: ApiParameterListMixin;
|
||||||
|
|
||||||
public constructor(options: IParameterOptions) {
|
public constructor(options: IParameterOptions) {
|
||||||
@@ -64,6 +70,7 @@ export class Parameter {
|
|||||||
this.isOptional = options.isOptional;
|
this.isOptional = options.isOptional;
|
||||||
this.isRest = options.isRest;
|
this.isRest = options.isRest;
|
||||||
this._parent = options.parent;
|
this._parent = options.parent;
|
||||||
|
this.defaultValue = options.defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ interface DocgenEventJson {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface DocgenParamJson {
|
interface DocgenParamJson {
|
||||||
default?: string;
|
default?: boolean | number | string;
|
||||||
description: string;
|
description: string;
|
||||||
name: string;
|
name: string;
|
||||||
nullable?: boolean;
|
nullable?: boolean;
|
||||||
@@ -155,7 +155,7 @@ interface DocgenMethodJson {
|
|||||||
interface DocgenPropertyJson {
|
interface DocgenPropertyJson {
|
||||||
abstract?: boolean;
|
abstract?: boolean;
|
||||||
access?: DocgenAccess;
|
access?: DocgenAccess;
|
||||||
default?: string;
|
default?: boolean | number | string;
|
||||||
deprecated?: DocgenDeprecated;
|
deprecated?: DocgenDeprecated;
|
||||||
description: string;
|
description: string;
|
||||||
meta: DocgenMetaJson;
|
meta: DocgenMetaJson;
|
||||||
@@ -843,6 +843,7 @@ export class ApiModelGenerator {
|
|||||||
const parameters: IApiParameterOptions[] = this._captureParameters(
|
const parameters: IApiParameterOptions[] = this._captureParameters(
|
||||||
nodesToCapture,
|
nodesToCapture,
|
||||||
functionDeclaration.parameters,
|
functionDeclaration.parameters,
|
||||||
|
jsDoc?.params,
|
||||||
);
|
);
|
||||||
|
|
||||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||||
@@ -1043,6 +1044,7 @@ export class ApiModelGenerator {
|
|||||||
const parameters: IApiParameterOptions[] = this._captureParameters(
|
const parameters: IApiParameterOptions[] = this._captureParameters(
|
||||||
nodesToCapture,
|
nodesToCapture,
|
||||||
methodDeclaration.parameters,
|
methodDeclaration.parameters,
|
||||||
|
jsDoc?.params,
|
||||||
);
|
);
|
||||||
|
|
||||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||||
@@ -1137,7 +1139,11 @@ export class ApiModelGenerator {
|
|||||||
methodSignature.typeParameters,
|
methodSignature.typeParameters,
|
||||||
);
|
);
|
||||||
|
|
||||||
const parameters: IApiParameterOptions[] = this._captureParameters(nodesToCapture, methodSignature.parameters);
|
const parameters: IApiParameterOptions[] = this._captureParameters(
|
||||||
|
nodesToCapture,
|
||||||
|
methodSignature.parameters,
|
||||||
|
jsDoc?.params,
|
||||||
|
);
|
||||||
|
|
||||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||||
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
||||||
@@ -1264,7 +1270,7 @@ export class ApiModelGenerator {
|
|||||||
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
||||||
const docComment: tsdoc.DocComment | undefined = jsDoc
|
const docComment: tsdoc.DocComment | undefined = jsDoc
|
||||||
? this._tsDocParser.parseString(
|
? this._tsDocParser.parseString(
|
||||||
`/**\n * ${this._fixLinkTags(jsDoc.description) ?? ''}\n${
|
`/**\n * ${this._fixLinkTags(jsDoc.description) ?? ''}${jsDoc.default ? ` (default: ${this._escapeSpecialChars(jsDoc.default)})` : ''}\n${
|
||||||
'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\n`).join('') : ''
|
'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\n`).join('') : ''
|
||||||
}${'readonly' in jsDoc && jsDoc.readonly ? ' * @readonly\n' : ''}${
|
}${'readonly' in jsDoc && jsDoc.readonly ? ' * @readonly\n' : ''}${
|
||||||
'deprecated' in jsDoc && jsDoc.deprecated
|
'deprecated' in jsDoc && jsDoc.deprecated
|
||||||
@@ -1342,7 +1348,7 @@ export class ApiModelGenerator {
|
|||||||
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
||||||
const docComment: tsdoc.DocComment | undefined = jsDoc
|
const docComment: tsdoc.DocComment | undefined = jsDoc
|
||||||
? this._tsDocParser.parseString(
|
? this._tsDocParser.parseString(
|
||||||
`/**\n * ${this._fixLinkTags(jsDoc.description) ?? ''}\n${
|
`/**\n * ${this._fixLinkTags(jsDoc.description) ?? ''}${jsDoc.default ? `\n * @defaultValue ${this._escapeSpecialChars(jsDoc.default)}` : ''}\n${
|
||||||
'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\n`).join('') : ''
|
'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\n`).join('') : ''
|
||||||
}${'readonly' in jsDoc && jsDoc.readonly ? ' * @readonly\n' : ''}${
|
}${'readonly' in jsDoc && jsDoc.readonly ? ' * @readonly\n' : ''}${
|
||||||
'deprecated' in jsDoc && jsDoc.deprecated
|
'deprecated' in jsDoc && jsDoc.deprecated
|
||||||
@@ -1510,15 +1516,17 @@ export class ApiModelGenerator {
|
|||||||
const excerptTokens: IExcerptToken[] = [
|
const excerptTokens: IExcerptToken[] = [
|
||||||
{
|
{
|
||||||
kind: ExcerptTokenKind.Content,
|
kind: ExcerptTokenKind.Content,
|
||||||
text: `on('${name}', (${
|
text: `public on(eventName: '${name}', listener: (${
|
||||||
jsDoc.params?.length ? `${jsDoc.params[0]?.name}${jsDoc.params[0]?.nullable ? '?' : ''}: ` : ') => {})'
|
jsDoc.params?.length
|
||||||
|
? `${jsDoc.params[0]?.name}${jsDoc.params[0]?.optional ? '?' : ''}: `
|
||||||
|
: ') => void): this;'
|
||||||
}`,
|
}`,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const parameters: IApiParameterOptions[] = [];
|
const parameters: IApiParameterOptions[] = [];
|
||||||
for (let index = 0; index < (jsDoc.params?.length ?? 0) - 1; index++) {
|
for (let index = 0; index < (jsDoc.params?.length ?? 0) - 1; index++) {
|
||||||
const parameter = jsDoc.params![index]!;
|
const parameter = jsDoc.params![index]!;
|
||||||
const newTokens = this._mapVarType(parameter.type);
|
const newTokens = this._mapVarType(parameter.type, parameter.nullable);
|
||||||
parameters.push({
|
parameters.push({
|
||||||
parameterName: parameter.name,
|
parameterName: parameter.name,
|
||||||
parameterTypeTokenRange: {
|
parameterTypeTokenRange: {
|
||||||
@@ -1527,6 +1535,7 @@ export class ApiModelGenerator {
|
|||||||
},
|
},
|
||||||
isOptional: Boolean(parameter.optional),
|
isOptional: Boolean(parameter.optional),
|
||||||
isRest: parameter.name.startsWith('...'),
|
isRest: parameter.name.startsWith('...'),
|
||||||
|
defaultValue: parameter.default?.toString(),
|
||||||
});
|
});
|
||||||
excerptTokens.push(...newTokens);
|
excerptTokens.push(...newTokens);
|
||||||
excerptTokens.push({
|
excerptTokens.push({
|
||||||
@@ -1537,7 +1546,7 @@ export class ApiModelGenerator {
|
|||||||
|
|
||||||
if (jsDoc.params?.length) {
|
if (jsDoc.params?.length) {
|
||||||
const parameter = jsDoc.params![jsDoc.params.length - 1]!;
|
const parameter = jsDoc.params![jsDoc.params.length - 1]!;
|
||||||
const newTokens = this._mapVarType(parameter.type);
|
const newTokens = this._mapVarType(parameter.type, parameter.nullable);
|
||||||
parameters.push({
|
parameters.push({
|
||||||
parameterName: parameter.name,
|
parameterName: parameter.name,
|
||||||
parameterTypeTokenRange: {
|
parameterTypeTokenRange: {
|
||||||
@@ -1546,11 +1555,12 @@ export class ApiModelGenerator {
|
|||||||
},
|
},
|
||||||
isOptional: Boolean(parameter.optional),
|
isOptional: Boolean(parameter.optional),
|
||||||
isRest: parameter.name.startsWith('...'),
|
isRest: parameter.name.startsWith('...'),
|
||||||
|
defaultValue: parameter.default?.toString(),
|
||||||
});
|
});
|
||||||
excerptTokens.push(...newTokens);
|
excerptTokens.push(...newTokens);
|
||||||
excerptTokens.push({
|
excerptTokens.push({
|
||||||
kind: ExcerptTokenKind.Content,
|
kind: ExcerptTokenKind.Content,
|
||||||
text: `) => {})`,
|
text: `) => void): this;`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1638,6 +1648,7 @@ export class ApiModelGenerator {
|
|||||||
private _captureParameters(
|
private _captureParameters(
|
||||||
nodesToCapture: IExcerptBuilderNodeToCapture[],
|
nodesToCapture: IExcerptBuilderNodeToCapture[],
|
||||||
parameterNodes: ts.NodeArray<ts.ParameterDeclaration>,
|
parameterNodes: ts.NodeArray<ts.ParameterDeclaration>,
|
||||||
|
jsDoc?: DocgenParamJson[] | undefined,
|
||||||
): IApiParameterOptions[] {
|
): IApiParameterOptions[] {
|
||||||
const parameters: IApiParameterOptions[] = [];
|
const parameters: IApiParameterOptions[] = [];
|
||||||
for (const parameter of parameterNodes) {
|
for (const parameter of parameterNodes) {
|
||||||
@@ -1648,6 +1659,9 @@ export class ApiModelGenerator {
|
|||||||
parameterTypeTokenRange,
|
parameterTypeTokenRange,
|
||||||
isOptional: this._collector.typeChecker.isOptionalParameter(parameter),
|
isOptional: this._collector.typeChecker.isOptionalParameter(parameter),
|
||||||
isRest: Boolean(parameter.dotDotDotToken),
|
isRest: Boolean(parameter.dotDotDotToken),
|
||||||
|
defaultValue:
|
||||||
|
parameter.initializer?.getText() ??
|
||||||
|
jsDoc?.find((param) => param.name === parameter.name.getText().trim())?.default?.toString(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1746,6 +1760,14 @@ export class ApiModelGenerator {
|
|||||||
return sourceLocation;
|
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 {
|
private _fixLinkTags(input?: string): string | undefined {
|
||||||
return input
|
return input
|
||||||
?.replaceAll(linkRegEx, (_match, _p1, _p2, _p3, _p4, _p5, _offset, _string, groups) => {
|
?.replaceAll(linkRegEx, (_match, _p1, _p2, _p3, _p4, _p5, _offset, _string, groups) => {
|
||||||
@@ -1765,7 +1787,7 @@ export class ApiModelGenerator {
|
|||||||
.replaceAll('* ', '\n * * ');
|
.replaceAll('* ', '\n * * ');
|
||||||
}
|
}
|
||||||
|
|
||||||
private _mapVarType(typey: DocgenVarTypeJson): IExcerptToken[] {
|
private _mapVarType(typey: DocgenVarTypeJson, nullable?: boolean): IExcerptToken[] {
|
||||||
const mapper = Array.isArray(typey) ? typey : (typey.types ?? []);
|
const mapper = Array.isArray(typey) ? typey : (typey.types ?? []);
|
||||||
const lookup: { [K in ts.SyntaxKind]?: string } = {
|
const lookup: { [K in ts.SyntaxKind]?: string } = {
|
||||||
[ts.SyntaxKind.ClassDeclaration]: 'class',
|
[ts.SyntaxKind.ClassDeclaration]: 'class',
|
||||||
@@ -1808,7 +1830,22 @@ export class ApiModelGenerator {
|
|||||||
{ kind: ExcerptTokenKind.Content, text: symbol ?? '' },
|
{ kind: ExcerptTokenKind.Content, text: symbol ?? '' },
|
||||||
];
|
];
|
||||||
}, []);
|
}, []);
|
||||||
return index === 0 ? result : [{ kind: ExcerptTokenKind.Content, text: ' | ' }, ...result];
|
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];
|
||||||
})
|
})
|
||||||
.filter((excerpt) => excerpt.text.length);
|
.filter((excerpt) => excerpt.text.length);
|
||||||
}
|
}
|
||||||
@@ -1823,7 +1860,7 @@ export class ApiModelGenerator {
|
|||||||
isOptional: Boolean(prop.nullable),
|
isOptional: Boolean(prop.nullable),
|
||||||
isReadonly: Boolean(prop.readonly),
|
isReadonly: Boolean(prop.readonly),
|
||||||
docComment: this._tsDocParser.parseString(
|
docComment: this._tsDocParser.parseString(
|
||||||
`/**\n * ${this._fixLinkTags(prop.description) ?? ''}\n${
|
`/**\n * ${this._fixLinkTags(prop.description) ?? ''}\n${prop.default ? ` * @defaultValue ${this._escapeSpecialChars(prop.default)}\n` : ''}${
|
||||||
prop.see?.map((see) => ` * @see ${see}\n`).join('') ?? ''
|
prop.see?.map((see) => ` * @see ${see}\n`).join('') ?? ''
|
||||||
}${prop.readonly ? ' * @readonly\n' : ''} */`,
|
}${prop.readonly ? ' * @readonly\n' : ''} */`,
|
||||||
).docComment,
|
).docComment,
|
||||||
@@ -1835,7 +1872,7 @@ export class ApiModelGenerator {
|
|||||||
}${prop.name} :`,
|
}${prop.name} :`,
|
||||||
},
|
},
|
||||||
...mappedVarType,
|
...mappedVarType,
|
||||||
{ kind: ExcerptTokenKind.Content, text: ';' },
|
{ kind: ExcerptTokenKind.Content, text: `${prop.default ? ` = ${prop.default}` : ''};` },
|
||||||
],
|
],
|
||||||
propertyTypeTokenRange: { startIndex: 1, endIndex: 1 + mappedVarType.length },
|
propertyTypeTokenRange: { startIndex: 1, endIndex: 1 + mappedVarType.length },
|
||||||
releaseTag: prop.access === 'private' ? ReleaseTag.Internal : ReleaseTag.Public,
|
releaseTag: prop.access === 'private' ? ReleaseTag.Internal : ReleaseTag.Public,
|
||||||
@@ -1858,6 +1895,7 @@ export class ApiModelGenerator {
|
|||||||
startIndex: 1 + index + paramTokens.slice(0, index).reduce((akk, num) => akk + num, 0),
|
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),
|
endIndex: 1 + index + paramTokens.slice(0, index + 1).reduce((akk, num) => akk + num, 0),
|
||||||
},
|
},
|
||||||
|
defaultValue: param.default?.toString(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1882,7 +1920,7 @@ export class ApiModelGenerator {
|
|||||||
excerptTokens.push(...newTokens);
|
excerptTokens.push(...newTokens);
|
||||||
excerptTokens.push({
|
excerptTokens.push({
|
||||||
kind: ExcerptTokenKind.Content,
|
kind: ExcerptTokenKind.Content,
|
||||||
text: `, ${method.params![index + 1]!.name}${
|
text: `${method.params![index]!.default ? ` = ${method.params![index]!.default}` : ''}, ${method.params![index + 1]!.name}${
|
||||||
method.params![index + 1]!.nullable || method.params![index + 1]!.optional ? '?' : ''
|
method.params![index + 1]!.nullable || method.params![index + 1]!.optional ? '?' : ''
|
||||||
}: `,
|
}: `,
|
||||||
});
|
});
|
||||||
@@ -1892,7 +1930,10 @@ export class ApiModelGenerator {
|
|||||||
const newTokens = this._mapVarType(method.params[method.params.length - 1]!.type);
|
const newTokens = this._mapVarType(method.params[method.params.length - 1]!.type);
|
||||||
paramTokens.push(newTokens.length);
|
paramTokens.push(newTokens.length);
|
||||||
excerptTokens.push(...newTokens);
|
excerptTokens.push(...newTokens);
|
||||||
excerptTokens.push({ kind: ExcerptTokenKind.Content, text: `): ` });
|
excerptTokens.push({
|
||||||
|
kind: ExcerptTokenKind.Content,
|
||||||
|
text: `${method.params![method.params.length - 1]!.default ? ` = ${method.params![method.params.length - 1]!.default}` : ''}): `,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const returnTokens = this._mapVarType(method.returns?.[0] ?? []);
|
const returnTokens = this._mapVarType(method.returns?.[0] ?? []);
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
<a href="https://www.npmjs.com/package/@discordjs/brokers"><img src="https://img.shields.io/npm/v/@discordjs/brokers.svg?maxAge=3600" alt="npm version" /></a>
|
<a href="https://www.npmjs.com/package/@discordjs/brokers"><img src="https://img.shields.io/npm/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://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/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Build status" /></a>
|
||||||
<a href="https://codecov.io/gh/discordjs/discord.js" ><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=brokers" alt="Code coverage" /></a>
|
<a href="https://github.com/discordjs/discord.js/commits/main/packages/brokers"><img alt="Last commit." src="https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fbrokers"></a>
|
||||||
|
<a href="https://codecov.io/gh/discordjs/discord.js"><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=brokers" alt="Code coverage" /></a>
|
||||||
</p>
|
</p>
|
||||||
<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>
|
<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>
|
||||||
@@ -23,7 +24,7 @@
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
**Node.js 18 or newer is required.**
|
**Node.js 20 or newer is required.**
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install @discordjs/brokers
|
npm install @discordjs/brokers
|
||||||
|
|||||||
@@ -30,8 +30,10 @@ body = """
|
|||||||
{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\
|
{{ 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.github.username %} by @{{ commit.github.username }}{%- endif %}\
|
||||||
{% if commit.breaking %}\
|
{% if commit.breaking %}\
|
||||||
{% for breakingChange in commit.footers %}\
|
{% for footer in commit.footers %}\
|
||||||
\n{% raw %} {% endraw %}- **{{ breakingChange.token }}{{ breakingChange.separator }}** {{ breakingChange.value }}\
|
{% if footer.breaking %}\
|
||||||
|
\n{% raw %} {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\
|
||||||
|
{% endif %}\
|
||||||
{% endfor %}\
|
{% endfor %}\
|
||||||
{% endif %}\
|
{% endif %}\
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@
|
|||||||
"vitest": "^2.0.5"
|
"vitest": "^2.0.5"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=20"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public",
|
"access": "public",
|
||||||
|
|||||||
@@ -2,18 +2,6 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
# [@discordjs/builders@1.11.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.10.1...@discordjs/builders@1.11.0) - (2025-04-25)
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- Components v2 in builders v1 (#10787) ([118e682](https://github.com/discordjs/discord.js/commit/118e6826821b3b90f5923e40f167747e0658cfd1))
|
|
||||||
|
|
||||||
# [@discordjs/builders@1.10.1](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.10.0...@discordjs/builders@1.10.1) - (2025-02-10)
|
|
||||||
|
|
||||||
## Bug Fixes
|
|
||||||
|
|
||||||
- **EmbedBuilder:** Allow empty `name` and `value` on fields (#10747) ([49ef3a8](https://github.com/discordjs/discord.js/commit/49ef3a833eab23d426d5c667e28aa493ddc9cb6c))
|
|
||||||
|
|
||||||
# [@discordjs/builders@1.9.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.8.2...@discordjs/builders@1.9.0) - (2024-09-01)
|
# [@discordjs/builders@1.9.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.8.2...@discordjs/builders@1.9.0) - (2024-09-01)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
<a href="https://www.npmjs.com/package/@discordjs/builders"><img src="https://img.shields.io/npm/v/@discordjs/builders.svg?maxAge=3600" alt="npm version" /></a>
|
<a href="https://www.npmjs.com/package/@discordjs/builders"><img src="https://img.shields.io/npm/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://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/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Build status" /></a>
|
||||||
<a href="https://codecov.io/gh/discordjs/discord.js" ><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=builders" alt="Code coverage" /></a>
|
<a href="https://github.com/discordjs/discord.js/commits/main/packages/builders"><img alt="Last commit." src="https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fbuilders"></a>
|
||||||
|
<a href="https://codecov.io/gh/discordjs/discord.js"><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=builders" alt="Code coverage" /></a>
|
||||||
</p>
|
</p>
|
||||||
<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>
|
<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>
|
||||||
@@ -23,7 +24,7 @@
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
**Node.js 16.11.0 or newer is required.**
|
**Node.js 18 or newer is required.**
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install @discordjs/builders
|
npm install @discordjs/builders
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import {
|
|||||||
ButtonStyle,
|
ButtonStyle,
|
||||||
ComponentType,
|
ComponentType,
|
||||||
type APIActionRowComponent,
|
type APIActionRowComponent,
|
||||||
type APIComponentInMessageActionRow,
|
type APIMessageActionRowComponent,
|
||||||
} from 'discord-api-types/v10';
|
} from 'discord-api-types/v10';
|
||||||
import { describe, test, expect } from 'vitest';
|
import { describe, test, expect } from 'vitest';
|
||||||
import {
|
import {
|
||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
StringSelectMenuOptionBuilder,
|
StringSelectMenuOptionBuilder,
|
||||||
} from '../../src/index.js';
|
} from '../../src/index.js';
|
||||||
|
|
||||||
const rowWithButtonData: APIActionRowComponent<APIComponentInMessageActionRow> = {
|
const rowWithButtonData: APIActionRowComponent<APIMessageActionRowComponent> = {
|
||||||
type: ComponentType.ActionRow,
|
type: ComponentType.ActionRow,
|
||||||
components: [
|
components: [
|
||||||
{
|
{
|
||||||
@@ -25,7 +25,7 @@ const rowWithButtonData: APIActionRowComponent<APIComponentInMessageActionRow> =
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const rowWithSelectMenuData: APIActionRowComponent<APIComponentInMessageActionRow> = {
|
const rowWithSelectMenuData: APIActionRowComponent<APIMessageActionRowComponent> = {
|
||||||
type: ComponentType.ActionRow,
|
type: ComponentType.ActionRow,
|
||||||
components: [
|
components: [
|
||||||
{
|
{
|
||||||
@@ -57,7 +57,7 @@ describe('Action Row Components', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN valid JSON input THEN valid JSON output is given', () => {
|
test('GIVEN valid JSON input THEN valid JSON output is given', () => {
|
||||||
const actionRowData: APIActionRowComponent<APIComponentInMessageActionRow> = {
|
const actionRowData: APIActionRowComponent<APIMessageActionRowComponent> = {
|
||||||
type: ComponentType.ActionRow,
|
type: ComponentType.ActionRow,
|
||||||
components: [
|
components: [
|
||||||
{
|
{
|
||||||
@@ -92,7 +92,7 @@ describe('Action Row Components', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN valid builder options THEN valid JSON output is given', () => {
|
test('GIVEN valid builder options THEN valid JSON output is given', () => {
|
||||||
const rowWithButtonData: APIActionRowComponent<APIComponentInMessageActionRow> = {
|
const rowWithButtonData: APIActionRowComponent<APIMessageActionRowComponent> = {
|
||||||
type: ComponentType.ActionRow,
|
type: ComponentType.ActionRow,
|
||||||
components: [
|
components: [
|
||||||
{
|
{
|
||||||
@@ -104,7 +104,7 @@ describe('Action Row Components', () => {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const rowWithSelectMenuData: APIActionRowComponent<APIComponentInMessageActionRow> = {
|
const rowWithSelectMenuData: APIActionRowComponent<APIMessageActionRowComponent> = {
|
||||||
type: ComponentType.ActionRow,
|
type: ComponentType.ActionRow,
|
||||||
components: [
|
components: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import {
|
|||||||
ComponentType,
|
ComponentType,
|
||||||
TextInputStyle,
|
TextInputStyle,
|
||||||
type APIButtonComponent,
|
type APIButtonComponent,
|
||||||
type APIComponentInMessageActionRow,
|
type APIMessageActionRowComponent,
|
||||||
type APISelectMenuComponent,
|
type APISelectMenuComponent,
|
||||||
type APITextInputComponent,
|
type APITextInputComponent,
|
||||||
type APIActionRowComponent,
|
type APIActionRowComponent,
|
||||||
@@ -27,7 +27,7 @@ describe('createComponentBuilder', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
test('GIVEN an action row component THEN returns a ActionRowBuilder', () => {
|
test('GIVEN an action row component THEN returns a ActionRowBuilder', () => {
|
||||||
const actionRow: APIActionRowComponent<APIComponentInMessageActionRow> = {
|
const actionRow: APIActionRowComponent<APIMessageActionRowComponent> = {
|
||||||
components: [],
|
components: [],
|
||||||
type: ComponentType.ActionRow,
|
type: ComponentType.ActionRow,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,248 +0,0 @@
|
|||||||
import { type APIContainerComponent, ComponentType, SeparatorSpacingSize } from 'discord-api-types/v10';
|
|
||||||
import { describe, test, expect } from 'vitest';
|
|
||||||
import { ButtonBuilder } from '../../../dist/index.mjs';
|
|
||||||
import { ActionRowBuilder } from '../../../src/components/ActionRow.js';
|
|
||||||
import { createComponentBuilder } from '../../../src/components/Components.js';
|
|
||||||
import { ContainerBuilder } from '../../../src/components/v2/Container.js';
|
|
||||||
import { FileBuilder } from '../../../src/components/v2/File.js';
|
|
||||||
import { MediaGalleryBuilder } from '../../../src/components/v2/MediaGallery.js';
|
|
||||||
import { SectionBuilder } from '../../../src/components/v2/Section.js';
|
|
||||||
import { SeparatorBuilder } from '../../../src/components/v2/Separator.js';
|
|
||||||
import { TextDisplayBuilder } from '../../../src/components/v2/TextDisplay.js';
|
|
||||||
|
|
||||||
const containerWithTextDisplay: APIContainerComponent = {
|
|
||||||
type: ComponentType.Container,
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
type: ComponentType.TextDisplay,
|
|
||||||
content: 'test',
|
|
||||||
id: 123,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const containerWithSeparatorData: APIContainerComponent = {
|
|
||||||
type: ComponentType.Container,
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
type: ComponentType.Separator,
|
|
||||||
id: 1_234,
|
|
||||||
spacing: SeparatorSpacingSize.Small,
|
|
||||||
divider: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
accent_color: 0x00ff00,
|
|
||||||
};
|
|
||||||
|
|
||||||
const containerWithSeparatorDataNoColor: APIContainerComponent = {
|
|
||||||
type: ComponentType.Container,
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
type: ComponentType.Separator,
|
|
||||||
id: 1_234,
|
|
||||||
spacing: SeparatorSpacingSize.Small,
|
|
||||||
divider: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('Container Components', () => {
|
|
||||||
describe('Assertion Tests', () => {
|
|
||||||
test('GIVEN valid components THEN do not throw', () => {
|
|
||||||
expect(() =>
|
|
||||||
new ContainerBuilder().addActionRowComponents(
|
|
||||||
new ActionRowBuilder<ButtonBuilder>().addComponents(new ButtonBuilder()),
|
|
||||||
),
|
|
||||||
).not.toThrowError();
|
|
||||||
expect(() => new ContainerBuilder().addFileComponents(new FileBuilder())).not.toThrowError();
|
|
||||||
expect(() => new ContainerBuilder().addMediaGalleryComponents(new MediaGalleryBuilder())).not.toThrowError();
|
|
||||||
expect(() => new ContainerBuilder().addSectionComponents(new SectionBuilder())).not.toThrowError();
|
|
||||||
expect(() => new ContainerBuilder().addSeparatorComponents(new SeparatorBuilder())).not.toThrowError();
|
|
||||||
expect(() => new ContainerBuilder().addTextDisplayComponents(new TextDisplayBuilder())).not.toThrowError();
|
|
||||||
expect(() => new ContainerBuilder().spliceComponents(0, 0, new SeparatorBuilder())).not.toThrowError();
|
|
||||||
expect(() => new ContainerBuilder().addSeparatorComponents([new SeparatorBuilder()])).not.toThrowError();
|
|
||||||
expect(() =>
|
|
||||||
new ContainerBuilder().spliceComponents(0, 0, [{ type: ComponentType.Separator }]),
|
|
||||||
).not.toThrowError();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN valid JSON input THEN valid JSON output is given', () => {
|
|
||||||
const containerData: APIContainerComponent = {
|
|
||||||
type: ComponentType.Container,
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
type: ComponentType.TextDisplay,
|
|
||||||
content: 'test',
|
|
||||||
id: 3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: ComponentType.Separator,
|
|
||||||
spacing: SeparatorSpacingSize.Large,
|
|
||||||
divider: true,
|
|
||||||
id: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: ComponentType.File,
|
|
||||||
file: {
|
|
||||||
url: 'attachment://file.png',
|
|
||||||
},
|
|
||||||
spoiler: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
accent_color: 0xff00ff,
|
|
||||||
spoiler: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(new ContainerBuilder(containerData).toJSON()).toEqual(containerData);
|
|
||||||
expect(() => createComponentBuilder({ type: ComponentType.Container, components: [] })).not.toThrowError();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN valid builder options THEN valid JSON output is given', () => {
|
|
||||||
const containerWithTextDisplay: APIContainerComponent = {
|
|
||||||
type: ComponentType.Container,
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
type: ComponentType.TextDisplay,
|
|
||||||
content: 'test',
|
|
||||||
id: 123,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const containerWithSeparatorData: APIContainerComponent = {
|
|
||||||
type: ComponentType.Container,
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
type: ComponentType.Separator,
|
|
||||||
id: 1_234,
|
|
||||||
spacing: SeparatorSpacingSize.Small,
|
|
||||||
divider: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
accent_color: 0x00ff00,
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(new ContainerBuilder(containerWithTextDisplay).toJSON()).toEqual(containerWithTextDisplay);
|
|
||||||
expect(new ContainerBuilder(containerWithSeparatorData).toJSON()).toEqual(containerWithSeparatorData);
|
|
||||||
expect(() => createComponentBuilder({ type: ComponentType.Container, components: [] })).not.toThrowError();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN valid builder options THEN valid JSON output is given 2', () => {
|
|
||||||
const textDisplay = new TextDisplayBuilder().setContent('test').setId(123);
|
|
||||||
const separator = new SeparatorBuilder().setId(1_234).setSpacing(SeparatorSpacingSize.Small).setDivider(false);
|
|
||||||
|
|
||||||
expect(new ContainerBuilder().addTextDisplayComponents(textDisplay).toJSON()).toEqual(containerWithTextDisplay);
|
|
||||||
expect(new ContainerBuilder().addSeparatorComponents(separator).toJSON()).toEqual(
|
|
||||||
containerWithSeparatorDataNoColor,
|
|
||||||
);
|
|
||||||
expect(new ContainerBuilder().addTextDisplayComponents([textDisplay]).toJSON()).toEqual(containerWithTextDisplay);
|
|
||||||
expect(new ContainerBuilder().addSeparatorComponents([separator]).toJSON()).toEqual(
|
|
||||||
containerWithSeparatorDataNoColor,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN valid accent color THEN valid JSON output is given', () => {
|
|
||||||
expect(
|
|
||||||
new ContainerBuilder({
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
type: ComponentType.TextDisplay,
|
|
||||||
content: 'test',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
.setAccentColor([255, 0, 255])
|
|
||||||
.toJSON(),
|
|
||||||
).toEqual({
|
|
||||||
type: ComponentType.Container,
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
type: ComponentType.TextDisplay,
|
|
||||||
content: 'test',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
accent_color: 0xff00ff,
|
|
||||||
});
|
|
||||||
expect(
|
|
||||||
new ContainerBuilder({
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
type: ComponentType.TextDisplay,
|
|
||||||
content: 'test',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
.setAccentColor(0xff00ff)
|
|
||||||
.toJSON(),
|
|
||||||
).toEqual({
|
|
||||||
type: ComponentType.Container,
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
type: ComponentType.TextDisplay,
|
|
||||||
content: 'test',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
accent_color: 0xff00ff,
|
|
||||||
});
|
|
||||||
expect(
|
|
||||||
new ContainerBuilder({
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
type: ComponentType.TextDisplay,
|
|
||||||
content: 'test',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
.setAccentColor([255, 0, 255])
|
|
||||||
.clearAccentColor()
|
|
||||||
.toJSON(),
|
|
||||||
).toEqual({
|
|
||||||
type: ComponentType.Container,
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
type: ComponentType.TextDisplay,
|
|
||||||
content: 'test',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
expect(new ContainerBuilder(containerWithSeparatorData).clearAccentColor().toJSON()).toEqual(
|
|
||||||
containerWithSeparatorDataNoColor,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN valid method parameters THEN valid JSON is given', () => {
|
|
||||||
expect(
|
|
||||||
new ContainerBuilder()
|
|
||||||
.addTextDisplayComponents(new TextDisplayBuilder().setId(3).clearId().setContent('test'))
|
|
||||||
.setSpoiler()
|
|
||||||
.toJSON(),
|
|
||||||
).toEqual({
|
|
||||||
type: ComponentType.Container,
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
type: ComponentType.TextDisplay,
|
|
||||||
content: 'test',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
spoiler: true,
|
|
||||||
});
|
|
||||||
expect(
|
|
||||||
new ContainerBuilder()
|
|
||||||
.addTextDisplayComponents({ type: ComponentType.TextDisplay, content: 'test' })
|
|
||||||
.setSpoiler(false)
|
|
||||||
.setId(5)
|
|
||||||
.toJSON(),
|
|
||||||
).toEqual({
|
|
||||||
type: ComponentType.Container,
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
type: ComponentType.TextDisplay,
|
|
||||||
content: 'test',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
spoiler: false,
|
|
||||||
id: 5,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
import { ComponentType } from 'discord-api-types/v10';
|
|
||||||
import { describe, expect, test } from 'vitest';
|
|
||||||
import { FileBuilder } from '../../../src/components/v2/File';
|
|
||||||
|
|
||||||
const dummy = {
|
|
||||||
type: ComponentType.File as const,
|
|
||||||
file: { url: 'attachment://owo.png' },
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('File', () => {
|
|
||||||
describe('File url', () => {
|
|
||||||
test('GIVEN a file with a pre-defined url THEN return valid toJSON data', () => {
|
|
||||||
const file = new FileBuilder({ file: { url: 'attachment://owo.png' } });
|
|
||||||
expect(file.toJSON()).toEqual({ ...dummy, file: { url: 'attachment://owo.png' } });
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN a file using File#setURL THEN return valid toJSON data', () => {
|
|
||||||
const file = new FileBuilder();
|
|
||||||
file.setURL('attachment://uwu.png');
|
|
||||||
|
|
||||||
expect(file.toJSON()).toEqual({ ...dummy, file: { url: 'attachment://uwu.png' } });
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN a file with an invalid url THEN throws error', () => {
|
|
||||||
const file = new FileBuilder();
|
|
||||||
|
|
||||||
expect(() => file.setURL('https://google.com')).toThrowError();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('File spoiler', () => {
|
|
||||||
test('GIVEN a file with a pre-defined spoiler status THEN return valid toJSON data', () => {
|
|
||||||
const file = new FileBuilder({ ...dummy, spoiler: true });
|
|
||||||
expect(file.toJSON()).toEqual({ ...dummy, spoiler: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN a file using File#setSpoiler THEN return valid toJSON data', () => {
|
|
||||||
const file = new FileBuilder({ ...dummy });
|
|
||||||
file.setSpoiler(false);
|
|
||||||
|
|
||||||
expect(file.toJSON()).toEqual({ ...dummy, spoiler: false });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
import { type APIMediaGalleryItem, type APIMediaGalleryComponent, ComponentType } from 'discord-api-types/v10';
|
|
||||||
import { describe, test, expect } from 'vitest';
|
|
||||||
import { createComponentBuilder } from '../../../src/components/Components.js';
|
|
||||||
import { MediaGalleryBuilder } from '../../../src/components/v2/MediaGallery.js';
|
|
||||||
import { MediaGalleryItemBuilder } from '../../../src/components/v2/MediaGalleryItem.js';
|
|
||||||
|
|
||||||
const galleryHttpsDisplay: APIMediaGalleryComponent = {
|
|
||||||
type: ComponentType.MediaGallery,
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
description: 'test',
|
|
||||||
spoiler: false,
|
|
||||||
media: { url: 'https://discord.com/logo.png' },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const galleryAttachmentData: APIMediaGalleryComponent = {
|
|
||||||
type: ComponentType.MediaGallery,
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
media: { url: 'attachment://file.png' },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
id: 123,
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('Media Gallery Components', () => {
|
|
||||||
describe('Assertion Tests', () => {
|
|
||||||
test('GIVEN an empty media gallery THEN throws error', () => {
|
|
||||||
const gallery = new MediaGalleryBuilder();
|
|
||||||
expect(() => gallery.toJSON()).toThrow();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN valid items THEN do not throw', () => {
|
|
||||||
expect(() => new MediaGalleryBuilder().addItems(new MediaGalleryItemBuilder())).not.toThrowError();
|
|
||||||
expect(() => new MediaGalleryBuilder().spliceItems(0, 0, new MediaGalleryItemBuilder())).not.toThrowError();
|
|
||||||
expect(() => new MediaGalleryBuilder().addItems([new MediaGalleryItemBuilder()])).not.toThrowError();
|
|
||||||
expect(() => new MediaGalleryBuilder().spliceItems(0, 0, [new MediaGalleryItemBuilder()])).not.toThrowError();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN valid JSON input THEN valid JSON output is given', () => {
|
|
||||||
const mediaGalleryData: APIMediaGalleryComponent = {
|
|
||||||
type: ComponentType.MediaGallery,
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
media: { url: 'attachment://file.png' },
|
|
||||||
description: 'test',
|
|
||||||
spoiler: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
media: { url: 'https://discord.js.org/logo.jpg' },
|
|
||||||
spoiler: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
id: 1_234,
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(new MediaGalleryBuilder(mediaGalleryData).toJSON()).toEqual(mediaGalleryData);
|
|
||||||
expect(() => createComponentBuilder({ type: ComponentType.MediaGallery, items: [] })).not.toThrowError();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN valid builder options THEN valid JSON output is given', () => {
|
|
||||||
const galleryHttpsDisplay: APIMediaGalleryComponent = {
|
|
||||||
type: ComponentType.MediaGallery,
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
description: 'test',
|
|
||||||
spoiler: false,
|
|
||||||
media: { url: 'https://discord.com/logo.png' },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const galleryAttachmentData: APIMediaGalleryComponent = {
|
|
||||||
type: ComponentType.MediaGallery,
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
media: { url: 'attachment://file.png' },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
id: 123,
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(new MediaGalleryBuilder(galleryHttpsDisplay).toJSON()).toEqual(galleryHttpsDisplay);
|
|
||||||
expect(new MediaGalleryBuilder(galleryAttachmentData).toJSON()).toEqual(galleryAttachmentData);
|
|
||||||
expect(() => createComponentBuilder({ type: ComponentType.MediaGallery, items: [] })).not.toThrowError();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN valid builder options THEN valid JSON output is given 2', () => {
|
|
||||||
const item1 = new MediaGalleryItemBuilder()
|
|
||||||
.setDescription('test')
|
|
||||||
.setSpoiler(false)
|
|
||||||
.setURL('https://discord.com/logo.png');
|
|
||||||
const item2 = new MediaGalleryItemBuilder().setURL('attachment://file.png');
|
|
||||||
|
|
||||||
expect(new MediaGalleryBuilder().addItems(item1).toJSON()).toEqual(galleryHttpsDisplay);
|
|
||||||
expect(new MediaGalleryBuilder().addItems(item2).setId(123).toJSON()).toEqual(galleryAttachmentData);
|
|
||||||
expect(new MediaGalleryBuilder().addItems([item1]).toJSON()).toEqual(galleryHttpsDisplay);
|
|
||||||
expect(new MediaGalleryBuilder().addItems([item2]).setId(123).toJSON()).toEqual(galleryAttachmentData);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN valid JSON options THEN valid JSON output is given 2', () => {
|
|
||||||
const item1: APIMediaGalleryItem = {
|
|
||||||
description: 'test',
|
|
||||||
spoiler: false,
|
|
||||||
media: { url: 'https://discord.com/logo.png' },
|
|
||||||
};
|
|
||||||
const item2 = {
|
|
||||||
media: { url: 'attachment://file.png' },
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(new MediaGalleryBuilder().addItems(item1).toJSON()).toEqual(galleryHttpsDisplay);
|
|
||||||
expect(new MediaGalleryBuilder().addItems(item2).setId(123).toJSON()).toEqual(galleryAttachmentData);
|
|
||||||
expect(new MediaGalleryBuilder().addItems([item1]).toJSON()).toEqual(galleryHttpsDisplay);
|
|
||||||
expect(new MediaGalleryBuilder().addItems([item2]).setId(123).toJSON()).toEqual(galleryAttachmentData);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN valid builder callback THEN valid JSON output is given', () => {
|
|
||||||
const item1 = new MediaGalleryItemBuilder()
|
|
||||||
.setDescription('test')
|
|
||||||
.setSpoiler(false)
|
|
||||||
.setURL('https://discord.com/logo.png');
|
|
||||||
const item2 = new MediaGalleryItemBuilder().setURL('attachment://file.png');
|
|
||||||
|
|
||||||
expect(
|
|
||||||
new MediaGalleryBuilder()
|
|
||||||
.addItems((item) => item.setDescription('test').setSpoiler(false).setURL('https://discord.com/logo.png'))
|
|
||||||
.toJSON(),
|
|
||||||
).toEqual(galleryHttpsDisplay);
|
|
||||||
expect(
|
|
||||||
new MediaGalleryBuilder()
|
|
||||||
.spliceItems(0, 0, (item) => item.setURL('attachment://file.png'))
|
|
||||||
.setId(123)
|
|
||||||
.toJSON(),
|
|
||||||
).toEqual(galleryAttachmentData);
|
|
||||||
expect(
|
|
||||||
new MediaGalleryBuilder()
|
|
||||||
.addItems([(item) => item.setDescription('test').setSpoiler(false).setURL('https://discord.com/logo.png')])
|
|
||||||
.toJSON(),
|
|
||||||
).toEqual(galleryHttpsDisplay);
|
|
||||||
expect(
|
|
||||||
new MediaGalleryBuilder()
|
|
||||||
.spliceItems(0, 0, [(item) => item.setDescription('test').clearDescription().setURL('attachment://file.png')])
|
|
||||||
.setId(123)
|
|
||||||
.toJSON(),
|
|
||||||
).toEqual(galleryAttachmentData);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,191 +0,0 @@
|
|||||||
import { type APISectionComponent, ButtonStyle, ComponentType } from 'discord-api-types/v10';
|
|
||||||
import { describe, test, expect } from 'vitest';
|
|
||||||
import { createComponentBuilder } from '../../../src/components/Components.js';
|
|
||||||
import { ButtonBuilder } from '../../../src/components/button/Button.js';
|
|
||||||
import { SectionBuilder } from '../../../src/components/v2/Section.js';
|
|
||||||
import { TextDisplayBuilder } from '../../../src/components/v2/TextDisplay.js';
|
|
||||||
import { ThumbnailBuilder } from '../../../src/components/v2/Thumbnail.js';
|
|
||||||
|
|
||||||
const sectionWithButtonData: APISectionComponent = {
|
|
||||||
type: ComponentType.Section,
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
type: ComponentType.TextDisplay,
|
|
||||||
content: 'test',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
accessory: {
|
|
||||||
type: ComponentType.Button,
|
|
||||||
label: 'test',
|
|
||||||
custom_id: '123',
|
|
||||||
style: ButtonStyle.Primary,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const sectionWithThumbnailData: APISectionComponent = {
|
|
||||||
type: ComponentType.Section,
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
type: ComponentType.TextDisplay,
|
|
||||||
content: 'test',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
accessory: {
|
|
||||||
type: ComponentType.Thumbnail,
|
|
||||||
media: { url: 'attachment://file.png' },
|
|
||||||
spoiler: true,
|
|
||||||
description: 'test',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('Section Components', () => {
|
|
||||||
describe('Assertion Tests', () => {
|
|
||||||
test('GIVEN valid components THEN do not throw', () => {
|
|
||||||
expect(() => new SectionBuilder().addTextDisplayComponents(new TextDisplayBuilder())).not.toThrowError();
|
|
||||||
expect(() => new SectionBuilder().spliceTextDisplayComponents(0, 0, new TextDisplayBuilder())).not.toThrowError();
|
|
||||||
expect(() => new SectionBuilder().addTextDisplayComponents([new TextDisplayBuilder()])).not.toThrowError();
|
|
||||||
expect(() =>
|
|
||||||
new SectionBuilder().spliceTextDisplayComponents(0, 0, [new TextDisplayBuilder()]),
|
|
||||||
).not.toThrowError();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN valid JSON input THEN valid JSON output is given', () => {
|
|
||||||
const sectionData: APISectionComponent = {
|
|
||||||
type: ComponentType.Section,
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
type: ComponentType.TextDisplay,
|
|
||||||
content: 'test',
|
|
||||||
id: 123,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: ComponentType.TextDisplay,
|
|
||||||
content: 'test',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: ComponentType.TextDisplay,
|
|
||||||
content: 'test',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
accessory: {
|
|
||||||
type: ComponentType.Thumbnail,
|
|
||||||
media: { url: 'attachment://file.png' },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(new SectionBuilder(sectionData).toJSON()).toEqual(sectionData);
|
|
||||||
expect(() =>
|
|
||||||
createComponentBuilder({
|
|
||||||
type: ComponentType.Section,
|
|
||||||
components: [],
|
|
||||||
accessory: { type: ComponentType.Thumbnail, media: { url: 'https://discord.com/logo.png' } },
|
|
||||||
}),
|
|
||||||
).not.toThrowError();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN valid builder options THEN valid JSON output is given', () => {
|
|
||||||
const sectionWithButtonData: APISectionComponent = {
|
|
||||||
type: ComponentType.Section,
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
type: ComponentType.TextDisplay,
|
|
||||||
content: 'test',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
accessory: {
|
|
||||||
type: ComponentType.Button,
|
|
||||||
label: 'test',
|
|
||||||
custom_id: '123',
|
|
||||||
style: ButtonStyle.Primary,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const sectionWithThumbnailData: APISectionComponent = {
|
|
||||||
type: ComponentType.Section,
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
type: ComponentType.TextDisplay,
|
|
||||||
content: 'test',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
accessory: {
|
|
||||||
type: ComponentType.Thumbnail,
|
|
||||||
media: { url: 'attachment://file.png' },
|
|
||||||
spoiler: true,
|
|
||||||
description: 'test',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(new SectionBuilder(sectionWithButtonData).toJSON()).toEqual(sectionWithButtonData);
|
|
||||||
expect(new SectionBuilder(sectionWithThumbnailData).toJSON()).toEqual(sectionWithThumbnailData);
|
|
||||||
expect(() =>
|
|
||||||
createComponentBuilder({
|
|
||||||
type: ComponentType.Section,
|
|
||||||
components: [],
|
|
||||||
accessory: {
|
|
||||||
type: ComponentType.Button,
|
|
||||||
label: 'test',
|
|
||||||
custom_id: '123',
|
|
||||||
style: ButtonStyle.Primary,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
).not.toThrowError();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN valid builder options THEN valid JSON output is given 2', () => {
|
|
||||||
const button = new ButtonBuilder().setLabel('test').setStyle(ButtonStyle.Primary).setCustomId('123');
|
|
||||||
const thumbnail = new ThumbnailBuilder().setDescription('test').setSpoiler().setURL('attachment://file.png');
|
|
||||||
const textDisplay = new TextDisplayBuilder().setContent('test');
|
|
||||||
|
|
||||||
expect(new SectionBuilder().addTextDisplayComponents(textDisplay).setButtonAccessory(button).toJSON()).toEqual(
|
|
||||||
sectionWithButtonData,
|
|
||||||
);
|
|
||||||
expect(
|
|
||||||
new SectionBuilder().addTextDisplayComponents(textDisplay).setThumbnailAccessory(thumbnail).toJSON(),
|
|
||||||
).toEqual(sectionWithThumbnailData);
|
|
||||||
expect(
|
|
||||||
new SectionBuilder()
|
|
||||||
.addTextDisplayComponents([textDisplay])
|
|
||||||
.setButtonAccessory((button) => button.setLabel('test').setStyle(ButtonStyle.Primary).setCustomId('123'))
|
|
||||||
.toJSON(),
|
|
||||||
).toEqual(sectionWithButtonData);
|
|
||||||
expect(
|
|
||||||
new SectionBuilder()
|
|
||||||
.addTextDisplayComponents([textDisplay])
|
|
||||||
.setThumbnailAccessory((thumbnail) =>
|
|
||||||
thumbnail.setDescription('test').setSpoiler().setURL('attachment://file.png'),
|
|
||||||
)
|
|
||||||
.toJSON(),
|
|
||||||
).toEqual(sectionWithThumbnailData);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN valid builder callback THEN valid JSON output is given', () => {
|
|
||||||
const button = new ButtonBuilder().setLabel('test').setStyle(ButtonStyle.Primary).setCustomId('123');
|
|
||||||
|
|
||||||
expect(
|
|
||||||
new SectionBuilder()
|
|
||||||
.addTextDisplayComponents((textDisplay) => textDisplay.setContent('test'))
|
|
||||||
.setButtonAccessory(button)
|
|
||||||
.toJSON(),
|
|
||||||
).toEqual(sectionWithButtonData);
|
|
||||||
expect(
|
|
||||||
new SectionBuilder()
|
|
||||||
.spliceTextDisplayComponents(0, 0, (textDisplay) => textDisplay.setContent('test'))
|
|
||||||
.setButtonAccessory(button)
|
|
||||||
.toJSON(),
|
|
||||||
).toEqual(sectionWithButtonData);
|
|
||||||
expect(
|
|
||||||
new SectionBuilder()
|
|
||||||
.addTextDisplayComponents([(textDisplay) => textDisplay.setContent('test')])
|
|
||||||
.setButtonAccessory(button)
|
|
||||||
.toJSON(),
|
|
||||||
).toEqual(sectionWithButtonData);
|
|
||||||
expect(
|
|
||||||
new SectionBuilder()
|
|
||||||
.spliceTextDisplayComponents(0, 0, [(textDisplay) => textDisplay.setContent('test')])
|
|
||||||
.setButtonAccessory(button)
|
|
||||||
.toJSON(),
|
|
||||||
).toEqual(sectionWithButtonData);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import { ComponentType, SeparatorSpacingSize } from 'discord-api-types/v10';
|
|
||||||
import { describe, expect, test } from 'vitest';
|
|
||||||
import { SeparatorBuilder } from '../../../src/components/v2/Separator';
|
|
||||||
|
|
||||||
describe('Separator', () => {
|
|
||||||
describe('Divider', () => {
|
|
||||||
test('GIVEN a separator with a pre-defined divider THEN return valid toJSON data', () => {
|
|
||||||
const separator = new SeparatorBuilder({ divider: true });
|
|
||||||
expect(separator.toJSON()).toEqual({ type: ComponentType.Separator, divider: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN a separator with a set divider THEN return valid toJSON data', () => {
|
|
||||||
const separator = new SeparatorBuilder().setDivider(false);
|
|
||||||
expect(separator.toJSON()).toEqual({ type: ComponentType.Separator, divider: false });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Spacing', () => {
|
|
||||||
test('GIVEN a separator with a pre-defined spacing THEN return valid toJSON data', () => {
|
|
||||||
const separator = new SeparatorBuilder({ spacing: SeparatorSpacingSize.Small });
|
|
||||||
expect(separator.toJSON()).toEqual({ type: ComponentType.Separator, spacing: SeparatorSpacingSize.Small });
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN a separator with a set spacing THEN return valid toJSON data', () => {
|
|
||||||
const separator = new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Large);
|
|
||||||
expect(separator.toJSON()).toEqual({ type: ComponentType.Separator, spacing: SeparatorSpacingSize.Large });
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN a separator with a set spacing THEN clear spacing THEN return valid toJSON data', () => {
|
|
||||||
const separator = new SeparatorBuilder({ spacing: SeparatorSpacingSize.Small });
|
|
||||||
separator.clearSpacing();
|
|
||||||
expect(separator.toJSON()).toEqual({ type: ComponentType.Separator });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import { ComponentType } from 'discord-api-types/v10';
|
|
||||||
import { describe, expect, test } from 'vitest';
|
|
||||||
import { TextDisplayBuilder } from '../../../src/components/v2/TextDisplay';
|
|
||||||
|
|
||||||
describe('TextDisplay', () => {
|
|
||||||
describe('TextDisplay content', () => {
|
|
||||||
test('GIVEN a text display with a pre-defined content THEN return valid toJSON data', () => {
|
|
||||||
const textDisplay = new TextDisplayBuilder({ content: 'foo' });
|
|
||||||
expect(textDisplay.toJSON()).toEqual({ type: ComponentType.TextDisplay, content: 'foo' });
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN a text display with a set content THEN return valid toJSON data', () => {
|
|
||||||
const textDisplay = new TextDisplayBuilder().setContent('foo');
|
|
||||||
expect(textDisplay.toJSON()).toEqual({ type: ComponentType.TextDisplay, content: 'foo' });
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN a text display with a pre-defined content THEN overwritten content THEN return valid toJSON data', () => {
|
|
||||||
const textDisplay = new TextDisplayBuilder({ content: 'foo' });
|
|
||||||
textDisplay.setContent('bar');
|
|
||||||
expect(textDisplay.toJSON()).toEqual({ type: ComponentType.TextDisplay, content: 'bar' });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
import { ComponentType } from 'discord-api-types/v10';
|
|
||||||
import { describe, expect, test } from 'vitest';
|
|
||||||
import { ThumbnailBuilder } from '../../../src/components/v2/Thumbnail';
|
|
||||||
|
|
||||||
const dummy = {
|
|
||||||
type: ComponentType.Thumbnail as const,
|
|
||||||
media: { url: 'https://google.com' },
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('Thumbnail', () => {
|
|
||||||
describe('Thumbnail url', () => {
|
|
||||||
test('GIVEN a thumbnail with a pre-defined url THEN return valid toJSON data', () => {
|
|
||||||
const thumbnail = new ThumbnailBuilder({ media: { url: 'https://google.com' } });
|
|
||||||
expect(thumbnail.toJSON()).toEqual({ type: ComponentType.Thumbnail, media: { url: 'https://google.com' } });
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN a thumbnail with a set url THEN return valid toJSON data', () => {
|
|
||||||
const thumbnail = new ThumbnailBuilder().setURL('https://google.com');
|
|
||||||
expect(thumbnail.toJSON()).toEqual({ type: ComponentType.Thumbnail, media: { url: 'https://google.com' } });
|
|
||||||
});
|
|
||||||
|
|
||||||
test.each(['owo', 'discord://user'])('GIVEN a thumbnail with an invalid URL (%s) THEN throws error', (input) => {
|
|
||||||
const thumbnail = new ThumbnailBuilder();
|
|
||||||
|
|
||||||
expect(() => thumbnail.setURL(input)).toThrowError();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Thumbnail description', () => {
|
|
||||||
test('GIVEN a thumbnail with a pre-defined description THEN return valid toJSON data', () => {
|
|
||||||
const thumbnail = new ThumbnailBuilder({ ...dummy, description: 'foo' });
|
|
||||||
expect(thumbnail.toJSON()).toEqual({ ...dummy, description: 'foo' });
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN a thumbnail with a set description THEN return valid toJSON data', () => {
|
|
||||||
const thumbnail = new ThumbnailBuilder({ ...dummy });
|
|
||||||
thumbnail.setDescription('foo');
|
|
||||||
|
|
||||||
expect(thumbnail.toJSON()).toEqual({ ...dummy, description: 'foo' });
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN a thumbnail with a pre-defined description THEN unset description THEN return valid toJSON data', () => {
|
|
||||||
const thumbnail = new ThumbnailBuilder({ description: 'foo', ...dummy });
|
|
||||||
thumbnail.clearDescription();
|
|
||||||
|
|
||||||
expect(thumbnail.toJSON()).toEqual({ ...dummy });
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN a thumbnail with an invalid description THEN throws error', () => {
|
|
||||||
const thumbnail = new ThumbnailBuilder();
|
|
||||||
|
|
||||||
expect(() => thumbnail.setDescription('a'.repeat(1_025))).toThrowError();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Thumbnail spoiler', () => {
|
|
||||||
test('GIVEN a thumbnail with a pre-defined spoiler status THEN return valid toJSON data', () => {
|
|
||||||
const thumbnail = new ThumbnailBuilder({ ...dummy, spoiler: true });
|
|
||||||
expect(thumbnail.toJSON()).toEqual({ ...dummy, spoiler: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
test('GIVEN a thumbnail with a set spoiler status THEN return valid toJSON data', () => {
|
|
||||||
const thumbnail = new ThumbnailBuilder({ ...dummy });
|
|
||||||
thumbnail.setSpoiler(false);
|
|
||||||
|
|
||||||
expect(thumbnail.toJSON()).toEqual({ ...dummy, spoiler: false });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -166,7 +166,7 @@ describe('Context Menu Commands', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('integration types', () => {
|
describe('integration types', () => {
|
||||||
test('GIVEN a builder with valid integraton types THEN does not throw an error', () => {
|
test('GIVEN a builder with valid integration types THEN does not throw an error', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
getBuilder().setIntegrationTypes([
|
getBuilder().setIntegrationTypes([
|
||||||
ApplicationIntegrationType.GuildInstall,
|
ApplicationIntegrationType.GuildInstall,
|
||||||
|
|||||||
@@ -324,16 +324,12 @@ describe('Embed', () => {
|
|||||||
test('GIVEN an embed using Embed#addFields THEN returns valid toJSON data', () => {
|
test('GIVEN an embed using Embed#addFields THEN returns valid toJSON data', () => {
|
||||||
const embed = new EmbedBuilder();
|
const embed = new EmbedBuilder();
|
||||||
embed.addFields({ name: 'foo', value: 'bar' });
|
embed.addFields({ name: 'foo', value: 'bar' });
|
||||||
embed.addFields([
|
embed.addFields([{ name: 'foo', value: 'bar' }]);
|
||||||
{ name: 'foo', value: 'bar' },
|
|
||||||
{ name: '', value: '' },
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(embed.toJSON()).toStrictEqual({
|
expect(embed.toJSON()).toStrictEqual({
|
||||||
fields: [
|
fields: [
|
||||||
{ name: 'foo', value: 'bar' },
|
{ name: 'foo', value: 'bar' },
|
||||||
{ name: 'foo', value: 'bar' },
|
{ name: 'foo', value: 'bar' },
|
||||||
{ name: '', value: '' },
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -385,24 +381,38 @@ describe('Embed', () => {
|
|||||||
expect(() => embed.setFields(Array.from({ length: 26 }, () => ({ name: 'foo', value: 'bar' })))).toThrowError();
|
expect(() => embed.setFields(Array.from({ length: 26 }, () => ({ name: 'foo', value: 'bar' })))).toThrowError();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN invalid field amount THEN throws error', () => {
|
describe('GIVEN invalid field amount THEN throws error', () => {
|
||||||
const embed = new EmbedBuilder();
|
test('1', () => {
|
||||||
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
embed.addFields(...Array.from({ length: 26 }, () => ({ name: 'foo', value: 'bar' }))),
|
embed.addFields(...Array.from({ length: 26 }, () => ({ name: 'foo', value: 'bar' }))),
|
||||||
).toThrowError();
|
).toThrowError();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN invalid field name length THEN throws error', () => {
|
describe('GIVEN invalid field name THEN throws error', () => {
|
||||||
const embed = new EmbedBuilder();
|
test('2', () => {
|
||||||
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
expect(() => embed.addFields({ name: 'a'.repeat(257), value: 'bar' })).toThrowError();
|
expect(() => embed.addFields({ name: '', value: 'bar' })).toThrowError();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GIVEN invalid field value length THEN throws error', () => {
|
describe('GIVEN invalid field name length THEN throws error', () => {
|
||||||
const embed = new EmbedBuilder();
|
test('3', () => {
|
||||||
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
expect(() => embed.addFields({ name: '', value: 'a'.repeat(1_025) })).toThrowError();
|
expect(() => embed.addFields({ name: 'a'.repeat(257), value: 'bar' })).toThrowError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('GIVEN invalid field value length THEN throws error', () => {
|
||||||
|
test('4', () => {
|
||||||
|
const embed = new EmbedBuilder();
|
||||||
|
|
||||||
|
expect(() => embed.addFields({ name: '', value: 'a'.repeat(1_025) })).toThrowError();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -30,8 +30,10 @@ body = """
|
|||||||
{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\
|
{{ 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.github.username %} by @{{ commit.github.username }}{%- endif %}\
|
||||||
{% if commit.breaking %}\
|
{% if commit.breaking %}\
|
||||||
{% for breakingChange in commit.footers %}\
|
{% for footer in commit.footers %}\
|
||||||
\n{% raw %} {% endraw %}- **{{ breakingChange.token }}{{ breakingChange.separator }}** {{ breakingChange.value }}\
|
{% if footer.breaking %}\
|
||||||
|
\n{% raw %} {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\
|
||||||
|
{% endif %}\
|
||||||
{% endfor %}\
|
{% endfor %}\
|
||||||
{% endif %}\
|
{% endif %}\
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"name": "@discordjs/builders",
|
"name": "@discordjs/builders",
|
||||||
"version": "1.11.2",
|
"version": "1.9.0",
|
||||||
"description": "A set of builders that you can use when creating your bot",
|
"description": "A set of builders that you can use when creating your bot",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
"@discordjs/formatters": "workspace:^",
|
"@discordjs/formatters": "workspace:^",
|
||||||
"@discordjs/util": "workspace:^",
|
"@discordjs/util": "workspace:^",
|
||||||
"@sapphire/shapeshift": "^4.0.0",
|
"@sapphire/shapeshift": "^4.0.0",
|
||||||
"discord-api-types": "^0.38.1",
|
"discord-api-types": "^0.37.119",
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
"ts-mixer": "^6.0.4",
|
"ts-mixer": "^6.0.4",
|
||||||
"tslib": "^2.6.3"
|
"tslib": "^2.6.3"
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
"vitest": "^2.0.5"
|
"vitest": "^2.0.5"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16.11.0"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public",
|
"access": "public",
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
import {
|
import {
|
||||||
type APIActionRowComponent,
|
type APIActionRowComponent,
|
||||||
ComponentType,
|
ComponentType,
|
||||||
type APIComponentInMessageActionRow,
|
type APIMessageActionRowComponent,
|
||||||
type APIComponentInModalActionRow,
|
type APIModalActionRowComponent,
|
||||||
type APIComponentInActionRow,
|
type APIActionRowComponentTypes,
|
||||||
} from 'discord-api-types/v10';
|
} from 'discord-api-types/v10';
|
||||||
import { normalizeArray, type RestOrArray } from '../util/normalizeArray.js';
|
import { normalizeArray, type RestOrArray } from '../util/normalizeArray.js';
|
||||||
import { ComponentBuilder } from './Component.js';
|
import { ComponentBuilder } from './Component.js';
|
||||||
@@ -18,6 +18,13 @@ import type { StringSelectMenuBuilder } from './selectMenu/StringSelectMenu.js';
|
|||||||
import type { UserSelectMenuBuilder } from './selectMenu/UserSelectMenu.js';
|
import type { UserSelectMenuBuilder } from './selectMenu/UserSelectMenu.js';
|
||||||
import type { TextInputBuilder } from './textInput/TextInput.js';
|
import type { TextInputBuilder } from './textInput/TextInput.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The builders that may be used for messages.
|
||||||
|
*/
|
||||||
|
export type MessageComponentBuilder =
|
||||||
|
| ActionRowBuilder<MessageActionRowComponentBuilder>
|
||||||
|
| MessageActionRowComponentBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The builders that may be used for modals.
|
* The builders that may be used for modals.
|
||||||
*/
|
*/
|
||||||
@@ -50,7 +57,7 @@ export type AnyComponentBuilder = MessageActionRowComponentBuilder | ModalAction
|
|||||||
* @typeParam ComponentType - The types of components this action row holds
|
* @typeParam ComponentType - The types of components this action row holds
|
||||||
*/
|
*/
|
||||||
export class ActionRowBuilder<ComponentType extends AnyComponentBuilder> extends ComponentBuilder<
|
export class ActionRowBuilder<ComponentType extends AnyComponentBuilder> extends ComponentBuilder<
|
||||||
APIActionRowComponent<APIComponentInMessageActionRow | APIComponentInModalActionRow>
|
APIActionRowComponent<APIMessageActionRowComponent | APIModalActionRowComponent>
|
||||||
> {
|
> {
|
||||||
/**
|
/**
|
||||||
* The components within this action row.
|
* The components within this action row.
|
||||||
@@ -91,7 +98,7 @@ export class ActionRowBuilder<ComponentType extends AnyComponentBuilder> extends
|
|||||||
* .addComponents(button2, button3);
|
* .addComponents(button2, button3);
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
public constructor({ components, ...data }: Partial<APIActionRowComponent<APIComponentInActionRow>> = {}) {
|
public constructor({ components, ...data }: Partial<APIActionRowComponent<APIActionRowComponentTypes>> = {}) {
|
||||||
super({ type: ComponentType.ActionRow, ...data });
|
super({ type: ComponentType.ActionRow, ...data });
|
||||||
this.components = (components?.map((component) => createComponentBuilder(component)) ?? []) as ComponentType[];
|
this.components = (components?.map((component) => createComponentBuilder(component)) ?? []) as ComponentType[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,6 @@ import { ButtonStyle, ChannelType, type APIMessageComponentEmoji } from 'discord
|
|||||||
import { isValidationEnabled } from '../util/validation.js';
|
import { isValidationEnabled } from '../util/validation.js';
|
||||||
import { StringSelectMenuOptionBuilder } from './selectMenu/StringSelectMenuOption.js';
|
import { StringSelectMenuOptionBuilder } from './selectMenu/StringSelectMenuOption.js';
|
||||||
|
|
||||||
export const idValidator = s
|
|
||||||
.number()
|
|
||||||
.safeInt()
|
|
||||||
.greaterThanOrEqual(1)
|
|
||||||
.lessThan(4_294_967_296) // 2^32 - 1
|
|
||||||
.setValidationEnabled(isValidationEnabled);
|
|
||||||
|
|
||||||
export const customIdValidator = s
|
export const customIdValidator = s
|
||||||
.string()
|
.string()
|
||||||
.lengthGreaterThanOrEqual(1)
|
.lengthGreaterThanOrEqual(1)
|
||||||
|
|||||||
@@ -1,20 +1,15 @@
|
|||||||
import type { JSONEncodable } from '@discordjs/util';
|
import type { JSONEncodable } from '@discordjs/util';
|
||||||
import type {
|
import type {
|
||||||
APIActionRowComponent,
|
APIActionRowComponent,
|
||||||
APIComponentInActionRow,
|
APIActionRowComponentTypes,
|
||||||
APIBaseComponent,
|
APIBaseComponent,
|
||||||
ComponentType,
|
ComponentType,
|
||||||
APIMessageComponent,
|
|
||||||
} from 'discord-api-types/v10';
|
} from 'discord-api-types/v10';
|
||||||
import { idValidator } from './Assertions';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Any action row component data represented as an object.
|
* Any action row component data represented as an object.
|
||||||
*/
|
*/
|
||||||
export type AnyAPIActionRowComponent =
|
export type AnyAPIActionRowComponent = APIActionRowComponent<APIActionRowComponentTypes> | APIActionRowComponentTypes;
|
||||||
| APIActionRowComponent<APIComponentInActionRow>
|
|
||||||
| APIComponentInActionRow
|
|
||||||
| APIMessageComponent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base component builder that contains common symbols for all sorts of components.
|
* The base component builder that contains common symbols for all sorts of components.
|
||||||
@@ -47,22 +42,4 @@ export abstract class ComponentBuilder<
|
|||||||
public constructor(data: Partial<DataType>) {
|
public constructor(data: Partial<DataType>) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the id (not the custom id) for this component.
|
|
||||||
*
|
|
||||||
* @param id - The id for this component
|
|
||||||
*/
|
|
||||||
public setId(id: number) {
|
|
||||||
this.data.id = idValidator.parse(id);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the id of this component, defaulting to a default incremented id.
|
|
||||||
*/
|
|
||||||
public clearId() {
|
|
||||||
this.data.id = undefined;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import type { JSONEncodable } from '@discordjs/util';
|
|
||||||
import { ComponentType, type APIMessageComponent, type APIModalComponent } from 'discord-api-types/v10';
|
import { ComponentType, type APIMessageComponent, type APIModalComponent } from 'discord-api-types/v10';
|
||||||
import {
|
import {
|
||||||
ActionRowBuilder,
|
ActionRowBuilder,
|
||||||
type MessageActionRowComponentBuilder,
|
|
||||||
type AnyComponentBuilder,
|
type AnyComponentBuilder,
|
||||||
|
type MessageComponentBuilder,
|
||||||
type ModalComponentBuilder,
|
type ModalComponentBuilder,
|
||||||
} from './ActionRow.js';
|
} from './ActionRow.js';
|
||||||
import { ComponentBuilder } from './Component.js';
|
import { ComponentBuilder } from './Component.js';
|
||||||
@@ -14,27 +13,6 @@ import { RoleSelectMenuBuilder } from './selectMenu/RoleSelectMenu.js';
|
|||||||
import { StringSelectMenuBuilder } from './selectMenu/StringSelectMenu.js';
|
import { StringSelectMenuBuilder } from './selectMenu/StringSelectMenu.js';
|
||||||
import { UserSelectMenuBuilder } from './selectMenu/UserSelectMenu.js';
|
import { UserSelectMenuBuilder } from './selectMenu/UserSelectMenu.js';
|
||||||
import { TextInputBuilder } from './textInput/TextInput.js';
|
import { TextInputBuilder } from './textInput/TextInput.js';
|
||||||
import { ContainerBuilder } from './v2/Container.js';
|
|
||||||
import { FileBuilder } from './v2/File.js';
|
|
||||||
import { MediaGalleryBuilder } from './v2/MediaGallery.js';
|
|
||||||
import { SectionBuilder } from './v2/Section.js';
|
|
||||||
import { SeparatorBuilder } from './v2/Separator.js';
|
|
||||||
import { TextDisplayBuilder } from './v2/TextDisplay.js';
|
|
||||||
import { ThumbnailBuilder } from './v2/Thumbnail.js';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The builders that may be used for messages.
|
|
||||||
*/
|
|
||||||
export type MessageComponentBuilder =
|
|
||||||
| ActionRowBuilder<MessageActionRowComponentBuilder>
|
|
||||||
| ContainerBuilder
|
|
||||||
| FileBuilder
|
|
||||||
| MediaGalleryBuilder
|
|
||||||
| MessageActionRowComponentBuilder
|
|
||||||
| SectionBuilder
|
|
||||||
| SeparatorBuilder
|
|
||||||
| TextDisplayBuilder
|
|
||||||
| ThumbnailBuilder;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Components here are mapped to their respective builder.
|
* Components here are mapped to their respective builder.
|
||||||
@@ -72,34 +50,6 @@ export interface MappedComponentTypes {
|
|||||||
* The channel select component type is associated with a {@link ChannelSelectMenuBuilder}.
|
* The channel select component type is associated with a {@link ChannelSelectMenuBuilder}.
|
||||||
*/
|
*/
|
||||||
[ComponentType.ChannelSelect]: ChannelSelectMenuBuilder;
|
[ComponentType.ChannelSelect]: ChannelSelectMenuBuilder;
|
||||||
/**
|
|
||||||
* The file component type is associated with a {@link FileBuilder}.
|
|
||||||
*/
|
|
||||||
[ComponentType.File]: FileBuilder;
|
|
||||||
/**
|
|
||||||
* The separator component type is associated with a {@link SeparatorBuilder}.
|
|
||||||
*/
|
|
||||||
[ComponentType.Separator]: SeparatorBuilder;
|
|
||||||
/**
|
|
||||||
* The container component type is associated with a {@link ContainerBuilder}.
|
|
||||||
*/
|
|
||||||
[ComponentType.Container]: ContainerBuilder;
|
|
||||||
/**
|
|
||||||
* The text display component type is associated with a {@link TextDisplayBuilder}.
|
|
||||||
*/
|
|
||||||
[ComponentType.TextDisplay]: TextDisplayBuilder;
|
|
||||||
/**
|
|
||||||
* The thumbnail component type is associated with a {@link ThumbnailBuilder}.
|
|
||||||
*/
|
|
||||||
[ComponentType.Thumbnail]: ThumbnailBuilder;
|
|
||||||
/**
|
|
||||||
* The section component type is associated with a {@link SectionBuilder}.
|
|
||||||
*/
|
|
||||||
[ComponentType.Section]: SectionBuilder;
|
|
||||||
/**
|
|
||||||
* The media gallery component type is associated with a {@link MediaGalleryBuilder}.
|
|
||||||
*/
|
|
||||||
[ComponentType.MediaGallery]: MediaGalleryBuilder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -147,44 +97,8 @@ export function createComponentBuilder(
|
|||||||
return new MentionableSelectMenuBuilder(data);
|
return new MentionableSelectMenuBuilder(data);
|
||||||
case ComponentType.ChannelSelect:
|
case ComponentType.ChannelSelect:
|
||||||
return new ChannelSelectMenuBuilder(data);
|
return new ChannelSelectMenuBuilder(data);
|
||||||
case ComponentType.File:
|
|
||||||
return new FileBuilder(data);
|
|
||||||
case ComponentType.Container:
|
|
||||||
return new ContainerBuilder(data);
|
|
||||||
case ComponentType.Section:
|
|
||||||
return new SectionBuilder(data);
|
|
||||||
case ComponentType.Separator:
|
|
||||||
return new SeparatorBuilder(data);
|
|
||||||
case ComponentType.TextDisplay:
|
|
||||||
return new TextDisplayBuilder(data);
|
|
||||||
case ComponentType.Thumbnail:
|
|
||||||
return new ThumbnailBuilder(data);
|
|
||||||
case ComponentType.MediaGallery:
|
|
||||||
return new MediaGalleryBuilder(data);
|
|
||||||
default:
|
default:
|
||||||
// @ts-expect-error This case can still occur if we get a newer unsupported component type
|
// @ts-expect-error This case can still occur if we get a newer unsupported component type
|
||||||
throw new Error(`Cannot properly serialize component type: ${data.type}`);
|
throw new Error(`Cannot properly serialize component type: ${data.type}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isBuilder<Builder extends JSONEncodable<any>>(
|
|
||||||
builder: unknown,
|
|
||||||
Constructor: new () => Builder,
|
|
||||||
): builder is Builder {
|
|
||||||
return builder instanceof Constructor;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resolveBuilder<ComponentType extends Record<PropertyKey, any>, Builder extends JSONEncodable<any>>(
|
|
||||||
builder: Builder | ComponentType | ((builder: Builder) => Builder),
|
|
||||||
Constructor: new (data?: ComponentType) => Builder,
|
|
||||||
) {
|
|
||||||
if (isBuilder(builder, Constructor)) {
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof builder === 'function') {
|
|
||||||
return builder(new Constructor());
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Constructor(builder);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
import { s } from '@sapphire/shapeshift';
|
|
||||||
import { SeparatorSpacingSize } from 'discord-api-types/v10';
|
|
||||||
import { colorPredicate } from '../../messages/embed/Assertions';
|
|
||||||
import { isValidationEnabled } from '../../util/validation';
|
|
||||||
import { ComponentBuilder } from '../Component';
|
|
||||||
import { ButtonBuilder } from '../button/Button';
|
|
||||||
import type { ContainerComponentBuilder } from './Container';
|
|
||||||
import type { MediaGalleryItemBuilder } from './MediaGalleryItem';
|
|
||||||
import type { TextDisplayBuilder } from './TextDisplay';
|
|
||||||
import { ThumbnailBuilder } from './Thumbnail';
|
|
||||||
|
|
||||||
export const unfurledMediaItemPredicate = s
|
|
||||||
.object({
|
|
||||||
url: s
|
|
||||||
.string()
|
|
||||||
.url(
|
|
||||||
{ allowedProtocols: ['http:', 'https:', 'attachment:'] },
|
|
||||||
{ message: 'Invalid protocol for media URL. Must be http:, https:, or attachment:' },
|
|
||||||
),
|
|
||||||
})
|
|
||||||
.setValidationEnabled(isValidationEnabled);
|
|
||||||
|
|
||||||
export const descriptionPredicate = s
|
|
||||||
.string()
|
|
||||||
.lengthGreaterThanOrEqual(1)
|
|
||||||
.lengthLessThanOrEqual(1_024)
|
|
||||||
.setValidationEnabled(isValidationEnabled);
|
|
||||||
|
|
||||||
export const filePredicate = s
|
|
||||||
.object({
|
|
||||||
url: s
|
|
||||||
.string()
|
|
||||||
.url({ allowedProtocols: ['attachment:'] }, { message: 'Invalid protocol for file URL. Must be attachment:' }),
|
|
||||||
})
|
|
||||||
.setValidationEnabled(isValidationEnabled);
|
|
||||||
|
|
||||||
export const spoilerPredicate = s.boolean();
|
|
||||||
|
|
||||||
export const dividerPredicate = s.boolean();
|
|
||||||
|
|
||||||
export const spacingPredicate = s.nativeEnum(SeparatorSpacingSize);
|
|
||||||
|
|
||||||
export const textDisplayContentPredicate = s
|
|
||||||
.string()
|
|
||||||
.lengthGreaterThanOrEqual(1)
|
|
||||||
.lengthLessThanOrEqual(4_000)
|
|
||||||
.setValidationEnabled(isValidationEnabled);
|
|
||||||
|
|
||||||
export const accessoryPredicate = s
|
|
||||||
.instance(ButtonBuilder)
|
|
||||||
.or(s.instance(ThumbnailBuilder))
|
|
||||||
.setValidationEnabled(isValidationEnabled);
|
|
||||||
|
|
||||||
export const containerColorPredicate = colorPredicate.nullish();
|
|
||||||
|
|
||||||
export function assertReturnOfBuilder<ReturnType extends MediaGalleryItemBuilder | TextDisplayBuilder>(
|
|
||||||
input: unknown,
|
|
||||||
ExpectedInstanceOf: new () => ReturnType,
|
|
||||||
): asserts input is ReturnType {
|
|
||||||
s.instance(ExpectedInstanceOf).setValidationEnabled(isValidationEnabled).parse(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function validateComponentArray<
|
|
||||||
ReturnType extends ContainerComponentBuilder | MediaGalleryItemBuilder = ContainerComponentBuilder,
|
|
||||||
>(input: unknown, min: number, max: number, ExpectedInstanceOf?: new () => ReturnType): asserts input is ReturnType[] {
|
|
||||||
(ExpectedInstanceOf ? s.instance(ExpectedInstanceOf) : s.instance(ComponentBuilder))
|
|
||||||
.array()
|
|
||||||
.lengthGreaterThanOrEqual(min)
|
|
||||||
.lengthLessThanOrEqual(max)
|
|
||||||
.setValidationEnabled(isValidationEnabled)
|
|
||||||
.parse(input);
|
|
||||||
}
|
|
||||||
@@ -1,239 +0,0 @@
|
|||||||
/* eslint-disable jsdoc/check-param-names */
|
|
||||||
|
|
||||||
import type {
|
|
||||||
APIActionRowComponent,
|
|
||||||
APIComponentInContainer,
|
|
||||||
APIComponentInMessageActionRow,
|
|
||||||
APIContainerComponent,
|
|
||||||
APIFileComponent,
|
|
||||||
APIMediaGalleryComponent,
|
|
||||||
APISectionComponent,
|
|
||||||
APISeparatorComponent,
|
|
||||||
APITextDisplayComponent,
|
|
||||||
} from 'discord-api-types/v10';
|
|
||||||
import { ComponentType } from 'discord-api-types/v10';
|
|
||||||
import type { RGBTuple } from '../../index.js';
|
|
||||||
import { MediaGalleryBuilder, SectionBuilder } from '../../index.js';
|
|
||||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
|
|
||||||
import type { AnyComponentBuilder, MessageActionRowComponentBuilder } from '../ActionRow.js';
|
|
||||||
import { ActionRowBuilder } from '../ActionRow.js';
|
|
||||||
import { ComponentBuilder } from '../Component.js';
|
|
||||||
import { createComponentBuilder, resolveBuilder } from '../Components.js';
|
|
||||||
import { containerColorPredicate, spoilerPredicate } from './Assertions.js';
|
|
||||||
import { FileBuilder } from './File.js';
|
|
||||||
import { SeparatorBuilder } from './Separator.js';
|
|
||||||
import { TextDisplayBuilder } from './TextDisplay.js';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The builders that may be used within a container.
|
|
||||||
*/
|
|
||||||
export type ContainerComponentBuilder =
|
|
||||||
| ActionRowBuilder<AnyComponentBuilder>
|
|
||||||
| FileBuilder
|
|
||||||
| MediaGalleryBuilder
|
|
||||||
| SectionBuilder
|
|
||||||
| SeparatorBuilder
|
|
||||||
| TextDisplayBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A builder that creates API-compatible JSON data for a container.
|
|
||||||
*/
|
|
||||||
export class ContainerBuilder extends ComponentBuilder<APIContainerComponent> {
|
|
||||||
/**
|
|
||||||
* The components within this container.
|
|
||||||
*/
|
|
||||||
public readonly components: ContainerComponentBuilder[];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new container from API data.
|
|
||||||
*
|
|
||||||
* @param data - The API data to create this container with
|
|
||||||
* @example
|
|
||||||
* Creating a container from an API data object:
|
|
||||||
* ```ts
|
|
||||||
* const container = new ContainerBuilder({
|
|
||||||
* components: [
|
|
||||||
* {
|
|
||||||
* content: "Some text here",
|
|
||||||
* type: ComponentType.TextDisplay,
|
|
||||||
* },
|
|
||||||
* ],
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
* @example
|
|
||||||
* Creating a container using setters and API data:
|
|
||||||
* ```ts
|
|
||||||
* const container = new ContainerBuilder({
|
|
||||||
* components: [
|
|
||||||
* {
|
|
||||||
* content: "# Heading",
|
|
||||||
* type: ComponentType.TextDisplay,
|
|
||||||
* },
|
|
||||||
* ],
|
|
||||||
* })
|
|
||||||
* .addComponents(separator, section);
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public constructor({ components, ...data }: Partial<APIContainerComponent> = {}) {
|
|
||||||
super({ type: ComponentType.Container, ...data });
|
|
||||||
this.components = (components?.map((component) => createComponentBuilder(component)) ??
|
|
||||||
[]) as ContainerComponentBuilder[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the accent color of this container.
|
|
||||||
*
|
|
||||||
* @param color - The color to use
|
|
||||||
*/
|
|
||||||
public setAccentColor(color?: RGBTuple | number): this {
|
|
||||||
// Data assertions
|
|
||||||
containerColorPredicate.parse(color);
|
|
||||||
|
|
||||||
if (Array.isArray(color)) {
|
|
||||||
const [red, green, blue] = color;
|
|
||||||
this.data.accent_color = (red << 16) + (green << 8) + blue;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.data.accent_color = color;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the accent color of this container.
|
|
||||||
*/
|
|
||||||
public clearAccentColor() {
|
|
||||||
this.data.accent_color = undefined;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds action row components to this container.
|
|
||||||
*
|
|
||||||
* @param components - The action row components to add
|
|
||||||
*/
|
|
||||||
public addActionRowComponents<ComponentType extends MessageActionRowComponentBuilder>(
|
|
||||||
...components: RestOrArray<
|
|
||||||
| ActionRowBuilder<ComponentType>
|
|
||||||
| APIActionRowComponent<APIComponentInMessageActionRow>
|
|
||||||
| ((builder: ActionRowBuilder<ComponentType>) => ActionRowBuilder<ComponentType>)
|
|
||||||
>
|
|
||||||
) {
|
|
||||||
this.components.push(
|
|
||||||
...normalizeArray(components).map((component) => resolveBuilder(component, ActionRowBuilder<ComponentType>)),
|
|
||||||
);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds file components to this container.
|
|
||||||
*
|
|
||||||
* @param components - The file components to add
|
|
||||||
*/
|
|
||||||
public addFileComponents(
|
|
||||||
...components: RestOrArray<APIFileComponent | FileBuilder | ((builder: FileBuilder) => FileBuilder)>
|
|
||||||
) {
|
|
||||||
this.components.push(...normalizeArray(components).map((component) => resolveBuilder(component, FileBuilder)));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds media gallery components to this container.
|
|
||||||
*
|
|
||||||
* @param components - The media gallery components to add
|
|
||||||
*/
|
|
||||||
public addMediaGalleryComponents(
|
|
||||||
...components: RestOrArray<
|
|
||||||
APIMediaGalleryComponent | MediaGalleryBuilder | ((builder: MediaGalleryBuilder) => MediaGalleryBuilder)
|
|
||||||
>
|
|
||||||
) {
|
|
||||||
this.components.push(
|
|
||||||
...normalizeArray(components).map((component) => resolveBuilder(component, MediaGalleryBuilder)),
|
|
||||||
);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds section components to this container.
|
|
||||||
*
|
|
||||||
* @param components - The section components to add
|
|
||||||
*/
|
|
||||||
public addSectionComponents(
|
|
||||||
...components: RestOrArray<APISectionComponent | SectionBuilder | ((builder: SectionBuilder) => SectionBuilder)>
|
|
||||||
) {
|
|
||||||
this.components.push(...normalizeArray(components).map((component) => resolveBuilder(component, SectionBuilder)));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds separator components to this container.
|
|
||||||
*
|
|
||||||
* @param components - The separator components to add
|
|
||||||
*/
|
|
||||||
public addSeparatorComponents(
|
|
||||||
...components: RestOrArray<
|
|
||||||
APISeparatorComponent | SeparatorBuilder | ((builder: SeparatorBuilder) => SeparatorBuilder)
|
|
||||||
>
|
|
||||||
) {
|
|
||||||
this.components.push(...normalizeArray(components).map((component) => resolveBuilder(component, SeparatorBuilder)));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds text display components to this container.
|
|
||||||
*
|
|
||||||
* @param components - The text display components to add
|
|
||||||
*/
|
|
||||||
public addTextDisplayComponents(
|
|
||||||
...components: RestOrArray<
|
|
||||||
APITextDisplayComponent | TextDisplayBuilder | ((builder: TextDisplayBuilder) => TextDisplayBuilder)
|
|
||||||
>
|
|
||||||
) {
|
|
||||||
this.components.push(
|
|
||||||
...normalizeArray(components).map((component) => resolveBuilder(component, TextDisplayBuilder)),
|
|
||||||
);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes, replaces, or inserts components for this container.
|
|
||||||
*
|
|
||||||
* @param index - The index to start removing, replacing or inserting components
|
|
||||||
* @param deleteCount - The amount of components to remove
|
|
||||||
* @param components - The components to set
|
|
||||||
*/
|
|
||||||
public spliceComponents(
|
|
||||||
index: number,
|
|
||||||
deleteCount: number,
|
|
||||||
...components: RestOrArray<APIComponentInContainer | ContainerComponentBuilder>
|
|
||||||
) {
|
|
||||||
this.components.splice(
|
|
||||||
index,
|
|
||||||
deleteCount,
|
|
||||||
...normalizeArray(components).map((component) =>
|
|
||||||
component instanceof ComponentBuilder ? component : createComponentBuilder(component),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the spoiler status of this container.
|
|
||||||
*
|
|
||||||
* @param spoiler - The spoiler status to use
|
|
||||||
*/
|
|
||||||
public setSpoiler(spoiler = true) {
|
|
||||||
this.data.spoiler = spoilerPredicate.parse(spoiler);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc ComponentBuilder.toJSON}
|
|
||||||
*/
|
|
||||||
public toJSON(): APIContainerComponent {
|
|
||||||
return {
|
|
||||||
...this.data,
|
|
||||||
components: this.components.map((component) => component.toJSON()),
|
|
||||||
} as APIContainerComponent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
import { ComponentType, type APIFileComponent } from 'discord-api-types/v10';
|
|
||||||
import { ComponentBuilder } from '../Component';
|
|
||||||
import { filePredicate, spoilerPredicate } from './Assertions';
|
|
||||||
|
|
||||||
export class FileBuilder extends ComponentBuilder<APIFileComponent> {
|
|
||||||
/**
|
|
||||||
* Creates a new file from API data.
|
|
||||||
*
|
|
||||||
* @param data - The API data to create this file with
|
|
||||||
* @example
|
|
||||||
* Creating a file from an API data object:
|
|
||||||
* ```ts
|
|
||||||
* const file = new FileBuilder({
|
|
||||||
* spoiler: true,
|
|
||||||
* file: {
|
|
||||||
* url: 'attachment://file.png',
|
|
||||||
* },
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
* @example
|
|
||||||
* Creating a file using setters and API data:
|
|
||||||
* ```ts
|
|
||||||
* const file = new FileBuilder({
|
|
||||||
* file: {
|
|
||||||
* url: 'attachment://image.jpg',
|
|
||||||
* },
|
|
||||||
* })
|
|
||||||
* .setSpoiler(false);
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public constructor(data: Partial<APIFileComponent> = {}) {
|
|
||||||
super({ type: ComponentType.File, ...data, file: data.file ? { url: data.file.url } : undefined });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the spoiler status of this file.
|
|
||||||
*
|
|
||||||
* @param spoiler - The spoiler status to use
|
|
||||||
*/
|
|
||||||
public setSpoiler(spoiler = true) {
|
|
||||||
this.data.spoiler = spoilerPredicate.parse(spoiler);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the media URL of this file.
|
|
||||||
*
|
|
||||||
* @param url - The URL to use
|
|
||||||
*/
|
|
||||||
public setURL(url: string) {
|
|
||||||
this.data.file = filePredicate.parse({ url });
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc ComponentBuilder.toJSON}
|
|
||||||
*/
|
|
||||||
public override toJSON(): APIFileComponent {
|
|
||||||
filePredicate.parse(this.data.file);
|
|
||||||
|
|
||||||
return { ...this.data, file: { ...this.data.file } } as APIFileComponent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
/* eslint-disable jsdoc/check-param-names */
|
|
||||||
|
|
||||||
import type { APIMediaGalleryComponent, APIMediaGalleryItem } from 'discord-api-types/v10';
|
|
||||||
import { ComponentType } from 'discord-api-types/v10';
|
|
||||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
|
|
||||||
import { ComponentBuilder } from '../Component.js';
|
|
||||||
import { resolveBuilder } from '../Components.js';
|
|
||||||
import { assertReturnOfBuilder, validateComponentArray } from './Assertions.js';
|
|
||||||
import { MediaGalleryItemBuilder } from './MediaGalleryItem.js';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A builder that creates API-compatible JSON data for a container.
|
|
||||||
*/
|
|
||||||
export class MediaGalleryBuilder extends ComponentBuilder<APIMediaGalleryComponent> {
|
|
||||||
/**
|
|
||||||
* The components within this container.
|
|
||||||
*/
|
|
||||||
public readonly items: MediaGalleryItemBuilder[];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new media gallery from API data.
|
|
||||||
*
|
|
||||||
* @param data - The API data to create this media gallery with
|
|
||||||
* @example
|
|
||||||
* Creating a media gallery from an API data object:
|
|
||||||
* ```ts
|
|
||||||
* const mediaGallery = new MediaGalleryBuilder({
|
|
||||||
* items: [
|
|
||||||
* {
|
|
||||||
* description: "Some text here",
|
|
||||||
* media: {
|
|
||||||
* url: 'https://cdn.discordapp.com/embed/avatars/2.png',
|
|
||||||
* },
|
|
||||||
* },
|
|
||||||
* ],
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
* @example
|
|
||||||
* Creating a media gallery using setters and API data:
|
|
||||||
* ```ts
|
|
||||||
* const mediaGallery = new MediaGalleryBuilder({
|
|
||||||
* items: [
|
|
||||||
* {
|
|
||||||
* description: "alt text",
|
|
||||||
* media: {
|
|
||||||
* url: 'https://cdn.discordapp.com/embed/avatars/5.png',
|
|
||||||
* },
|
|
||||||
* },
|
|
||||||
* ],
|
|
||||||
* })
|
|
||||||
* .addItems(item2, item3);
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public constructor({ items, ...data }: Partial<APIMediaGalleryComponent> = {}) {
|
|
||||||
super({ type: ComponentType.MediaGallery, ...data });
|
|
||||||
this.items = items?.map((item) => new MediaGalleryItemBuilder(item)) ?? [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds items to this media gallery.
|
|
||||||
*
|
|
||||||
* @param items - The items to add
|
|
||||||
*/
|
|
||||||
public addItems(
|
|
||||||
...items: RestOrArray<
|
|
||||||
APIMediaGalleryItem | MediaGalleryItemBuilder | ((builder: MediaGalleryItemBuilder) => MediaGalleryItemBuilder)
|
|
||||||
>
|
|
||||||
) {
|
|
||||||
this.items.push(
|
|
||||||
...normalizeArray(items).map((input) => {
|
|
||||||
const result = resolveBuilder(input, MediaGalleryItemBuilder);
|
|
||||||
|
|
||||||
assertReturnOfBuilder(result, MediaGalleryItemBuilder);
|
|
||||||
return result;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes, replaces, or inserts media gallery items for this media gallery.
|
|
||||||
*
|
|
||||||
* @param index - The index to start removing, replacing or inserting items
|
|
||||||
* @param deleteCount - The amount of items to remove
|
|
||||||
* @param items - The items to insert
|
|
||||||
*/
|
|
||||||
public spliceItems(
|
|
||||||
index: number,
|
|
||||||
deleteCount: number,
|
|
||||||
...items: RestOrArray<
|
|
||||||
APIMediaGalleryItem | MediaGalleryItemBuilder | ((builder: MediaGalleryItemBuilder) => MediaGalleryItemBuilder)
|
|
||||||
>
|
|
||||||
) {
|
|
||||||
this.items.splice(
|
|
||||||
index,
|
|
||||||
deleteCount,
|
|
||||||
...normalizeArray(items).map((input) => {
|
|
||||||
const result = resolveBuilder(input, MediaGalleryItemBuilder);
|
|
||||||
|
|
||||||
assertReturnOfBuilder(result, MediaGalleryItemBuilder);
|
|
||||||
return result;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc ComponentBuilder.toJSON}
|
|
||||||
*/
|
|
||||||
public toJSON(): APIMediaGalleryComponent {
|
|
||||||
validateComponentArray(this.items, 1, 10, MediaGalleryItemBuilder);
|
|
||||||
return {
|
|
||||||
...this.data,
|
|
||||||
items: this.items.map((item) => item.toJSON()),
|
|
||||||
} as APIMediaGalleryComponent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
import type { JSONEncodable } from '@discordjs/util';
|
|
||||||
import type { APIMediaGalleryItem } from 'discord-api-types/v10';
|
|
||||||
import { descriptionPredicate, spoilerPredicate, unfurledMediaItemPredicate } from './Assertions';
|
|
||||||
|
|
||||||
export class MediaGalleryItemBuilder implements JSONEncodable<APIMediaGalleryItem> {
|
|
||||||
/**
|
|
||||||
* The API data associated with this media gallery item.
|
|
||||||
*/
|
|
||||||
public readonly data: Partial<APIMediaGalleryItem>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new media gallery item from API data.
|
|
||||||
*
|
|
||||||
* @param data - The API data to create this media gallery item with
|
|
||||||
* @example
|
|
||||||
* Creating a media gallery item from an API data object:
|
|
||||||
* ```ts
|
|
||||||
* const item = new MediaGalleryItemBuilder({
|
|
||||||
* description: "Some text here",
|
|
||||||
* media: {
|
|
||||||
* url: 'https://cdn.discordapp.com/embed/avatars/2.png',
|
|
||||||
* },
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
* @example
|
|
||||||
* Creating a media gallery item using setters and API data:
|
|
||||||
* ```ts
|
|
||||||
* const item = new MediaGalleryItemBuilder({
|
|
||||||
* media: {
|
|
||||||
* url: 'https://cdn.discordapp.com/embed/avatars/5.png',
|
|
||||||
* },
|
|
||||||
* })
|
|
||||||
* .setDescription("alt text");
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public constructor(data: Partial<APIMediaGalleryItem> = {}) {
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the description of this media gallery item.
|
|
||||||
*
|
|
||||||
* @param description - The description to use
|
|
||||||
*/
|
|
||||||
public setDescription(description: string) {
|
|
||||||
this.data.description = descriptionPredicate.parse(description);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the description of this media gallery item.
|
|
||||||
*/
|
|
||||||
public clearDescription() {
|
|
||||||
this.data.description = undefined;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the spoiler status of this media gallery item.
|
|
||||||
*
|
|
||||||
* @param spoiler - The spoiler status to use
|
|
||||||
*/
|
|
||||||
public setSpoiler(spoiler = true) {
|
|
||||||
this.data.spoiler = spoilerPredicate.parse(spoiler);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the media URL of this media gallery item.
|
|
||||||
*
|
|
||||||
* @param url - The URL to use
|
|
||||||
*/
|
|
||||||
public setURL(url: string) {
|
|
||||||
this.data.media = unfurledMediaItemPredicate.parse({ url });
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serializes this builder to API-compatible JSON data.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* This method runs validations on the data before serializing it.
|
|
||||||
* As such, it may throw an error if the data is invalid.
|
|
||||||
*/
|
|
||||||
public toJSON(): APIMediaGalleryItem {
|
|
||||||
unfurledMediaItemPredicate.parse(this.data.media);
|
|
||||||
|
|
||||||
return { ...this.data } as APIMediaGalleryItem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
/* eslint-disable jsdoc/check-param-names */
|
|
||||||
|
|
||||||
import type {
|
|
||||||
APIButtonComponent,
|
|
||||||
APISectionComponent,
|
|
||||||
APITextDisplayComponent,
|
|
||||||
APIThumbnailComponent,
|
|
||||||
} from 'discord-api-types/v10';
|
|
||||||
import { ComponentType } from 'discord-api-types/v10';
|
|
||||||
import { ButtonBuilder, ThumbnailBuilder } from '../../index.js';
|
|
||||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
|
|
||||||
import { ComponentBuilder } from '../Component.js';
|
|
||||||
import { createComponentBuilder, resolveBuilder } from '../Components.js';
|
|
||||||
import { accessoryPredicate, assertReturnOfBuilder, validateComponentArray } from './Assertions.js';
|
|
||||||
import { TextDisplayBuilder } from './TextDisplay.js';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A builder that creates API-compatible JSON data for a section.
|
|
||||||
*/
|
|
||||||
export class SectionBuilder extends ComponentBuilder<APISectionComponent> {
|
|
||||||
/**
|
|
||||||
* The components within this section.
|
|
||||||
*/
|
|
||||||
public readonly components: ComponentBuilder[];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The accessory of this section.
|
|
||||||
*/
|
|
||||||
public readonly accessory?: ButtonBuilder | ThumbnailBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new section from API data.
|
|
||||||
*
|
|
||||||
* @param data - The API data to create this section with
|
|
||||||
* @example
|
|
||||||
* Creating a section from an API data object:
|
|
||||||
* ```ts
|
|
||||||
* const section = new SectionBuilder({
|
|
||||||
* components: [
|
|
||||||
* {
|
|
||||||
* content: "Some text here",
|
|
||||||
* type: ComponentType.TextDisplay,
|
|
||||||
* },
|
|
||||||
* ],
|
|
||||||
* accessory: {
|
|
||||||
* media: {
|
|
||||||
* url: 'https://cdn.discordapp.com/embed/avatars/3.png',
|
|
||||||
* },
|
|
||||||
* }
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
* @example
|
|
||||||
* Creating a section using setters and API data:
|
|
||||||
* ```ts
|
|
||||||
* const section = new SectionBuilder({
|
|
||||||
* components: [
|
|
||||||
* {
|
|
||||||
* content: "# Heading",
|
|
||||||
* type: ComponentType.TextDisplay,
|
|
||||||
* },
|
|
||||||
* ],
|
|
||||||
* })
|
|
||||||
* .setPrimaryButtonAccessory(button);
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public constructor({ components, accessory, ...data }: Partial<APISectionComponent> = {}) {
|
|
||||||
super({ type: ComponentType.Section, ...data });
|
|
||||||
this.components = (components?.map((component) => createComponentBuilder(component)) ?? []) as ComponentBuilder[];
|
|
||||||
this.accessory = accessory ? createComponentBuilder(accessory) : undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the accessory of this section to a button.
|
|
||||||
*
|
|
||||||
* @param accessory - The accessory to use
|
|
||||||
*/
|
|
||||||
public setButtonAccessory(
|
|
||||||
accessory: APIButtonComponent | ButtonBuilder | ((builder: ButtonBuilder) => ButtonBuilder),
|
|
||||||
): this {
|
|
||||||
Reflect.set(this, 'accessory', accessoryPredicate.parse(resolveBuilder(accessory, ButtonBuilder)));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the accessory of this section to a thumbnail.
|
|
||||||
*
|
|
||||||
* @param accessory - The accessory to use
|
|
||||||
*/
|
|
||||||
public setThumbnailAccessory(
|
|
||||||
accessory: APIThumbnailComponent | ThumbnailBuilder | ((builder: ThumbnailBuilder) => ThumbnailBuilder),
|
|
||||||
): this {
|
|
||||||
Reflect.set(this, 'accessory', accessoryPredicate.parse(resolveBuilder(accessory, ThumbnailBuilder)));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds text display components to this section.
|
|
||||||
*
|
|
||||||
* @param components - The text display components to add
|
|
||||||
*/
|
|
||||||
public addTextDisplayComponents(
|
|
||||||
...components: RestOrArray<TextDisplayBuilder | ((builder: TextDisplayBuilder) => TextDisplayBuilder)>
|
|
||||||
) {
|
|
||||||
this.components.push(
|
|
||||||
...normalizeArray(components).map((input) => {
|
|
||||||
const result = resolveBuilder(input, TextDisplayBuilder);
|
|
||||||
|
|
||||||
assertReturnOfBuilder(result, TextDisplayBuilder);
|
|
||||||
return result;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes, replaces, or inserts text display components for this section.
|
|
||||||
*
|
|
||||||
* @param index - The index to start removing, replacing or inserting text display components
|
|
||||||
* @param deleteCount - The amount of text display components to remove
|
|
||||||
* @param components - The text display components to insert
|
|
||||||
*/
|
|
||||||
public spliceTextDisplayComponents(
|
|
||||||
index: number,
|
|
||||||
deleteCount: number,
|
|
||||||
...components: RestOrArray<
|
|
||||||
APITextDisplayComponent | TextDisplayBuilder | ((builder: TextDisplayBuilder) => TextDisplayBuilder)
|
|
||||||
>
|
|
||||||
) {
|
|
||||||
this.components.splice(
|
|
||||||
index,
|
|
||||||
deleteCount,
|
|
||||||
...normalizeArray(components).map((input) => {
|
|
||||||
const result = resolveBuilder(input, TextDisplayBuilder);
|
|
||||||
|
|
||||||
assertReturnOfBuilder(result, TextDisplayBuilder);
|
|
||||||
return result;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc ComponentBuilder.toJSON}
|
|
||||||
*/
|
|
||||||
public toJSON(): APISectionComponent {
|
|
||||||
validateComponentArray(this.components, 1, 3, TextDisplayBuilder);
|
|
||||||
return {
|
|
||||||
...this.data,
|
|
||||||
components: this.components.map((component) => component.toJSON()),
|
|
||||||
accessory: accessoryPredicate.parse(this.accessory).toJSON(),
|
|
||||||
} as APISectionComponent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
import type { SeparatorSpacingSize, APISeparatorComponent } from 'discord-api-types/v10';
|
|
||||||
import { ComponentType } from 'discord-api-types/v10';
|
|
||||||
import { ComponentBuilder } from '../Component';
|
|
||||||
import { dividerPredicate, spacingPredicate } from './Assertions';
|
|
||||||
|
|
||||||
export class SeparatorBuilder extends ComponentBuilder<APISeparatorComponent> {
|
|
||||||
/**
|
|
||||||
* Creates a new separator from API data.
|
|
||||||
*
|
|
||||||
* @param data - The API data to create this separator with
|
|
||||||
* @example
|
|
||||||
* Creating a separator from an API data object:
|
|
||||||
* ```ts
|
|
||||||
* const separator = new SeparatorBuilder({
|
|
||||||
* spacing: SeparatorSpacingSize.Small,
|
|
||||||
* divider: true,
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
* @example
|
|
||||||
* Creating a separator using setters and API data:
|
|
||||||
* ```ts
|
|
||||||
* const separator = new SeparatorBuilder({
|
|
||||||
* spacing: SeparatorSpacingSize.Large,
|
|
||||||
* })
|
|
||||||
* .setDivider(false);
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public constructor(data: Partial<APISeparatorComponent> = {}) {
|
|
||||||
super({
|
|
||||||
type: ComponentType.Separator,
|
|
||||||
...data,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets whether this separator should show a divider line.
|
|
||||||
*
|
|
||||||
* @param divider - Whether to show a divider line
|
|
||||||
*/
|
|
||||||
public setDivider(divider = true) {
|
|
||||||
this.data.divider = dividerPredicate.parse(divider);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the spacing of this separator.
|
|
||||||
*
|
|
||||||
* @param spacing - The spacing to use
|
|
||||||
*/
|
|
||||||
public setSpacing(spacing: SeparatorSpacingSize) {
|
|
||||||
this.data.spacing = spacingPredicate.parse(spacing);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the spacing of this separator.
|
|
||||||
*/
|
|
||||||
public clearSpacing() {
|
|
||||||
this.data.spacing = undefined;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc ComponentBuilder.toJSON}
|
|
||||||
*/
|
|
||||||
public override toJSON(): APISeparatorComponent {
|
|
||||||
return { ...this.data } as APISeparatorComponent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
import type { APITextDisplayComponent } from 'discord-api-types/v10';
|
|
||||||
import { ComponentType } from 'discord-api-types/v10';
|
|
||||||
import { ComponentBuilder } from '../Component';
|
|
||||||
import { textDisplayContentPredicate } from './Assertions';
|
|
||||||
|
|
||||||
export class TextDisplayBuilder extends ComponentBuilder<APITextDisplayComponent> {
|
|
||||||
/**
|
|
||||||
* Creates a new text display from API data.
|
|
||||||
*
|
|
||||||
* @param data - The API data to create this text display with
|
|
||||||
* @example
|
|
||||||
* Creating a text display from an API data object:
|
|
||||||
* ```ts
|
|
||||||
* const textDisplay = new TextDisplayBuilder({
|
|
||||||
* content: 'some text',
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
* @example
|
|
||||||
* Creating a text display using setters and API data:
|
|
||||||
* ```ts
|
|
||||||
* const textDisplay = new TextDisplayBuilder({
|
|
||||||
* content: 'old text',
|
|
||||||
* })
|
|
||||||
* .setContent('new text');
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public constructor(data: Partial<APITextDisplayComponent> = {}) {
|
|
||||||
super({
|
|
||||||
type: ComponentType.TextDisplay,
|
|
||||||
...data,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the text of this text display.
|
|
||||||
*
|
|
||||||
* @param content - The text to use
|
|
||||||
*/
|
|
||||||
public setContent(content: string) {
|
|
||||||
this.data.content = textDisplayContentPredicate.parse(content);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc ComponentBuilder.toJSON}
|
|
||||||
*/
|
|
||||||
public override toJSON(): APITextDisplayComponent {
|
|
||||||
textDisplayContentPredicate.parse(this.data.content);
|
|
||||||
|
|
||||||
return { ...this.data } as APITextDisplayComponent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
import type { APIThumbnailComponent } from 'discord-api-types/v10';
|
|
||||||
import { ComponentType } from 'discord-api-types/v10';
|
|
||||||
import { ComponentBuilder } from '../Component';
|
|
||||||
import { descriptionPredicate, spoilerPredicate, unfurledMediaItemPredicate } from './Assertions';
|
|
||||||
|
|
||||||
export class ThumbnailBuilder extends ComponentBuilder<APIThumbnailComponent> {
|
|
||||||
/**
|
|
||||||
* Creates a new thumbnail from API data.
|
|
||||||
*
|
|
||||||
* @param data - The API data to create this thumbnail with
|
|
||||||
* @example
|
|
||||||
* Creating a thumbnail from an API data object:
|
|
||||||
* ```ts
|
|
||||||
* const thumbnail = new ThumbnailBuilder({
|
|
||||||
* description: 'some text',
|
|
||||||
* media: {
|
|
||||||
* url: 'https://cdn.discordapp.com/embed/avatars/4.png',
|
|
||||||
* },
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
* @example
|
|
||||||
* Creating a thumbnail using setters and API data:
|
|
||||||
* ```ts
|
|
||||||
* const thumbnail = new ThumbnailBuilder({
|
|
||||||
* media: {
|
|
||||||
* url: 'attachment://image.png',
|
|
||||||
* },
|
|
||||||
* })
|
|
||||||
* .setDescription('alt text');
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public constructor(data: Partial<APIThumbnailComponent> = {}) {
|
|
||||||
super({
|
|
||||||
type: ComponentType.Thumbnail,
|
|
||||||
...data,
|
|
||||||
media: data.media ? { url: data.media.url } : undefined,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the description of this thumbnail.
|
|
||||||
*
|
|
||||||
* @param description - The description to use
|
|
||||||
*/
|
|
||||||
public setDescription(description: string) {
|
|
||||||
this.data.description = descriptionPredicate.parse(description);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the description of this thumbnail.
|
|
||||||
*/
|
|
||||||
public clearDescription() {
|
|
||||||
this.data.description = undefined;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the spoiler status of this thumbnail.
|
|
||||||
*
|
|
||||||
* @param spoiler - The spoiler status to use
|
|
||||||
*/
|
|
||||||
public setSpoiler(spoiler = true) {
|
|
||||||
this.data.spoiler = spoilerPredicate.parse(spoiler);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the media URL of this thumbnail.
|
|
||||||
*
|
|
||||||
* @param url - The URL to use
|
|
||||||
*/
|
|
||||||
public setURL(url: string) {
|
|
||||||
this.data.media = unfurledMediaItemPredicate.parse({ url });
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc ComponentBuilder.toJSON}
|
|
||||||
*/
|
|
||||||
public override toJSON(): APIThumbnailComponent {
|
|
||||||
unfurledMediaItemPredicate.parse(this.data.media);
|
|
||||||
|
|
||||||
return { ...this.data } as APIThumbnailComponent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -34,16 +34,6 @@ export {
|
|||||||
export * from './components/selectMenu/StringSelectMenuOption.js';
|
export * from './components/selectMenu/StringSelectMenuOption.js';
|
||||||
export * from './components/selectMenu/UserSelectMenu.js';
|
export * from './components/selectMenu/UserSelectMenu.js';
|
||||||
|
|
||||||
export * as ComponentsV2Assertions from './components/v2/Assertions.js';
|
|
||||||
export * from './components/v2/Container.js';
|
|
||||||
export * from './components/v2/File.js';
|
|
||||||
export * from './components/v2/MediaGallery.js';
|
|
||||||
export * from './components/v2/MediaGalleryItem.js';
|
|
||||||
export * from './components/v2/Section.js';
|
|
||||||
export * from './components/v2/Separator.js';
|
|
||||||
export * from './components/v2/TextDisplay.js';
|
|
||||||
export * from './components/v2/Thumbnail.js';
|
|
||||||
|
|
||||||
export * as SlashCommandAssertions from './interactions/slashCommands/Assertions.js';
|
export * as SlashCommandAssertions from './interactions/slashCommands/Assertions.js';
|
||||||
export * from './interactions/slashCommands/SlashCommandBuilder.js';
|
export * from './interactions/slashCommands/SlashCommandBuilder.js';
|
||||||
export * from './interactions/slashCommands/SlashCommandSubcommands.js';
|
export * from './interactions/slashCommands/SlashCommandSubcommands.js';
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import type { JSONEncodable } from '@discordjs/util';
|
import type { JSONEncodable } from '@discordjs/util';
|
||||||
import type {
|
import type {
|
||||||
APIActionRowComponent,
|
APIActionRowComponent,
|
||||||
APIComponentInModalActionRow,
|
APIModalActionRowComponent,
|
||||||
APIModalInteractionResponseCallbackData,
|
APIModalInteractionResponseCallbackData,
|
||||||
} from 'discord-api-types/v10';
|
} from 'discord-api-types/v10';
|
||||||
import { ActionRowBuilder, type ModalActionRowComponentBuilder } from '../../components/ActionRow.js';
|
import { ActionRowBuilder, type ModalActionRowComponentBuilder } from '../../components/ActionRow.js';
|
||||||
@@ -64,7 +64,7 @@ export class ModalBuilder implements JSONEncodable<APIModalInteractionResponseCa
|
|||||||
*/
|
*/
|
||||||
public addComponents(
|
public addComponents(
|
||||||
...components: RestOrArray<
|
...components: RestOrArray<
|
||||||
ActionRowBuilder<ModalActionRowComponentBuilder> | APIActionRowComponent<APIComponentInModalActionRow>
|
ActionRowBuilder<ModalActionRowComponentBuilder> | APIActionRowComponent<APIModalActionRowComponent>
|
||||||
>
|
>
|
||||||
) {
|
) {
|
||||||
this.components.push(
|
this.components.push(
|
||||||
|
|||||||
@@ -2,9 +2,17 @@ import { s } from '@sapphire/shapeshift';
|
|||||||
import type { APIEmbedField } from 'discord-api-types/v10';
|
import type { APIEmbedField } from 'discord-api-types/v10';
|
||||||
import { isValidationEnabled } from '../../util/validation.js';
|
import { isValidationEnabled } from '../../util/validation.js';
|
||||||
|
|
||||||
export const fieldNamePredicate = s.string().lengthLessThanOrEqual(256).setValidationEnabled(isValidationEnabled);
|
export const fieldNamePredicate = s
|
||||||
|
.string()
|
||||||
|
.lengthGreaterThanOrEqual(1)
|
||||||
|
.lengthLessThanOrEqual(256)
|
||||||
|
.setValidationEnabled(isValidationEnabled);
|
||||||
|
|
||||||
export const fieldValuePredicate = s.string().lengthLessThanOrEqual(1_024).setValidationEnabled(isValidationEnabled);
|
export const fieldValuePredicate = s
|
||||||
|
.string()
|
||||||
|
.lengthGreaterThanOrEqual(1)
|
||||||
|
.lengthLessThanOrEqual(1_024)
|
||||||
|
.setValidationEnabled(isValidationEnabled);
|
||||||
|
|
||||||
export const fieldInlinePredicate = s.boolean().optional();
|
export const fieldInlinePredicate = s.boolean().optional();
|
||||||
|
|
||||||
@@ -24,10 +32,7 @@ export function validateFieldLength(amountAdding: number, fields?: APIEmbedField
|
|||||||
fieldLengthPredicate.parse((fields?.length ?? 0) + amountAdding);
|
fieldLengthPredicate.parse((fields?.length ?? 0) + amountAdding);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const authorNamePredicate = fieldNamePredicate
|
export const authorNamePredicate = fieldNamePredicate.nullable().setValidationEnabled(isValidationEnabled);
|
||||||
.lengthGreaterThanOrEqual(1)
|
|
||||||
.nullable()
|
|
||||||
.setValidationEnabled(isValidationEnabled);
|
|
||||||
|
|
||||||
export const imageURLPredicate = s
|
export const imageURLPredicate = s
|
||||||
.string()
|
.string()
|
||||||
@@ -91,7 +96,4 @@ export const embedFooterPredicate = s
|
|||||||
|
|
||||||
export const timestampPredicate = s.union([s.number(), s.date()]).nullable().setValidationEnabled(isValidationEnabled);
|
export const timestampPredicate = s.union([s.number(), s.date()]).nullable().setValidationEnabled(isValidationEnabled);
|
||||||
|
|
||||||
export const titlePredicate = fieldNamePredicate
|
export const titlePredicate = fieldNamePredicate.nullable().setValidationEnabled(isValidationEnabled);
|
||||||
.lengthGreaterThanOrEqual(1)
|
|
||||||
.nullable()
|
|
||||||
.setValidationEnabled(isValidationEnabled);
|
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
<a href="https://www.npmjs.com/package/@discordjs/collection"><img src="https://img.shields.io/npm/v/@discordjs/collection.svg?maxAge=3600" alt="npm version" /></a>
|
<a href="https://www.npmjs.com/package/@discordjs/collection"><img src="https://img.shields.io/npm/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://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/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Build status" /></a>
|
||||||
<a href="https://codecov.io/gh/discordjs/discord.js" ><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=collection" alt="Code coverage" /></a>
|
<a href="https://github.com/discordjs/discord.js/commits/main/packages/collection"><img alt="Last commit." src="https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fcollection"></a>
|
||||||
|
<a href="https://codecov.io/gh/discordjs/discord.js"><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=collection" alt="Code coverage" /></a>
|
||||||
</p>
|
</p>
|
||||||
<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>
|
<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,8 +30,10 @@ body = """
|
|||||||
{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\
|
{{ 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.github.username %} by @{{ commit.github.username }}{%- endif %}\
|
||||||
{% if commit.breaking %}\
|
{% if commit.breaking %}\
|
||||||
{% for breakingChange in commit.footers %}\
|
{% for footer in commit.footers %}\
|
||||||
\n{% raw %} {% endraw %}- **{{ breakingChange.token }}{{ breakingChange.separator }}** {{ breakingChange.value }}\
|
{% if footer.breaking %}\
|
||||||
|
\n{% raw %} {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\
|
||||||
|
{% endif %}\
|
||||||
{% endfor %}\
|
{% endfor %}\
|
||||||
{% endif %}\
|
{% endif %}\
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
<a href="https://www.npmjs.com/package/@discordjs/core"><img src="https://img.shields.io/npm/v/@discordjs/core.svg?maxAge=3600" alt="npm version" /></a>
|
<a href="https://www.npmjs.com/package/@discordjs/core"><img src="https://img.shields.io/npm/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://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/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Build status" /></a>
|
||||||
<a href="https://codecov.io/gh/discordjs/discord.js" ><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=core" alt="Code coverage" /></a>
|
<a href="https://github.com/discordjs/discord.js/commits/main/packages/core"><img alt="Last commit." src="https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fcore"></a>
|
||||||
|
<a href="https://codecov.io/gh/discordjs/discord.js"><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=core" alt="Code coverage" /></a>
|
||||||
</p>
|
</p>
|
||||||
<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>
|
<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>
|
||||||
@@ -23,7 +24,7 @@
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
**Node.js 18 or newer is required.**
|
**Node.js 20 or newer is required.**
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install @discordjs/core
|
npm install @discordjs/core
|
||||||
|
|||||||
@@ -30,8 +30,10 @@ body = """
|
|||||||
{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\
|
{{ 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.github.username %} by @{{ commit.github.username }}{%- endif %}\
|
||||||
{% if commit.breaking %}\
|
{% if commit.breaking %}\
|
||||||
{% for breakingChange in commit.footers %}\
|
{% for footer in commit.footers %}\
|
||||||
\n{% raw %} {% endraw %}- **{{ breakingChange.token }}{{ breakingChange.separator }}** {{ breakingChange.value }}\
|
{% if footer.breaking %}\
|
||||||
|
\n{% raw %} {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\
|
||||||
|
{% endif %}\
|
||||||
{% endfor %}\
|
{% endfor %}\
|
||||||
{% endif %}\
|
{% endif %}\
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"name": "@discordjs/core",
|
"name": "@discordjs/core",
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"description": "A thinly abstracted wrapper around the rest API, and gateway.",
|
"description": "A thinly abstracted wrapper around the rest API, and gateway.",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
@@ -90,7 +90,7 @@
|
|||||||
"vitest": "^2.0.5"
|
"vitest": "^2.0.5"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=20"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public",
|
"access": "public",
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export class ChannelsAPI {
|
|||||||
/**
|
/**
|
||||||
* Sends a message in a channel
|
* Sends a message in a channel
|
||||||
*
|
*
|
||||||
* @see {@link https://discord.com/developers/docs/resources/channel#create-message}
|
* @see {@link https://discord.com/developers/docs/resources/message#create-message}
|
||||||
* @param channelId - The id of the channel to send the message in
|
* @param channelId - The id of the channel to send the message in
|
||||||
* @param body - The data for sending the message
|
* @param body - The data for sending the message
|
||||||
* @param options - The options for sending the message
|
* @param options - The options for sending the message
|
||||||
@@ -65,7 +65,7 @@ export class ChannelsAPI {
|
|||||||
/**
|
/**
|
||||||
* Edits a message
|
* Edits a message
|
||||||
*
|
*
|
||||||
* @see {@link https://discord.com/developers/docs/resources/channel#edit-message}
|
* @see {@link https://discord.com/developers/docs/resources/message#edit-message}
|
||||||
* @param channelId - The id of the channel the message is in
|
* @param channelId - The id of the channel the message is in
|
||||||
* @param messageId - The id of the message to edit
|
* @param messageId - The id of the message to edit
|
||||||
* @param body - The data for editing the message
|
* @param body - The data for editing the message
|
||||||
@@ -87,7 +87,7 @@ export class ChannelsAPI {
|
|||||||
/**
|
/**
|
||||||
* Fetches the reactions for a message
|
* Fetches the reactions for a message
|
||||||
*
|
*
|
||||||
* @see {@link https://discord.com/developers/docs/resources/channel#get-reactions}
|
* @see {@link https://discord.com/developers/docs/resources/message#get-reactions}
|
||||||
* @param channelId - The id of the channel the message is in
|
* @param channelId - The id of the channel the message is in
|
||||||
* @param messageId - The id of the message to get the reactions for
|
* @param messageId - The id of the message to get the reactions for
|
||||||
* @param emoji - The emoji 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
|
* Deletes a reaction for the current user
|
||||||
*
|
*
|
||||||
* @see {@link https://discord.com/developers/docs/resources/channel#delete-own-reaction}
|
* @see {@link https://discord.com/developers/docs/resources/message#delete-own-reaction}
|
||||||
* @param channelId - The id of the channel the message is in
|
* @param channelId - The id of the channel the message is in
|
||||||
* @param messageId - The id of the message to delete the reaction for
|
* @param messageId - The id of the message to delete the reaction for
|
||||||
* @param emoji - The emoji 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
|
* Deletes a reaction for a user
|
||||||
*
|
*
|
||||||
* @see {@link https://discord.com/developers/docs/resources/channel#delete-user-reaction}
|
* @see {@link https://discord.com/developers/docs/resources/message#delete-user-reaction}
|
||||||
* @param channelId - The id of the channel the message is in
|
* @param channelId - The id of the channel the message is in
|
||||||
* @param messageId - The id of the message to delete the reaction for
|
* @param messageId - The id of the message to delete the reaction for
|
||||||
* @param emoji - The emoji 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
|
* Deletes all reactions for a message
|
||||||
*
|
*
|
||||||
* @see {@link https://discord.com/developers/docs/resources/channel#delete-all-reactions}
|
* @see {@link https://discord.com/developers/docs/resources/message#delete-all-reactions}
|
||||||
* @param channelId - The id of the channel the message is in
|
* @param channelId - The id of the channel the message is in
|
||||||
* @param messageId - The id of the message to delete the reactions for
|
* @param messageId - The id of the message to delete the reactions for
|
||||||
* @param options - The options for deleting the reactions
|
* @param options - The options for deleting the reactions
|
||||||
@@ -168,7 +168,7 @@ export class ChannelsAPI {
|
|||||||
/**
|
/**
|
||||||
* Deletes all reactions of an emoji for a message
|
* Deletes all reactions of an emoji for a message
|
||||||
*
|
*
|
||||||
* @see {@link https://discord.com/developers/docs/resources/channel#delete-all-reactions-for-emoji}
|
* @see {@link https://discord.com/developers/docs/resources/message#delete-all-reactions-for-emoji}
|
||||||
* @param channelId - The id of the channel the message is in
|
* @param channelId - The id of the channel the message is in
|
||||||
* @param messageId - The id of the message to delete the reactions for
|
* @param messageId - The id of the message to delete the reactions for
|
||||||
* @param emoji - The emoji 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
|
* Adds a reaction to a message
|
||||||
*
|
*
|
||||||
* @see {@link https://discord.com/developers/docs/resources/channel#create-reaction}
|
* @see {@link https://discord.com/developers/docs/resources/message#create-reaction}
|
||||||
* @param channelId - The id of the channel the message is in
|
* @param channelId - The id of the channel the message is in
|
||||||
* @param messageId - The id of the message to add the reaction to
|
* @param messageId - The id of the message to add the reaction to
|
||||||
* @param emoji - The emoji to add the reaction with
|
* @param emoji - The emoji to add the reaction with
|
||||||
@@ -242,7 +242,7 @@ export class ChannelsAPI {
|
|||||||
/**
|
/**
|
||||||
* Fetches the messages of a channel
|
* Fetches the messages of a channel
|
||||||
*
|
*
|
||||||
* @see {@link https://discord.com/developers/docs/resources/channel#get-channel-messages}
|
* @see {@link https://discord.com/developers/docs/resources/message#get-channel-messages}
|
||||||
* @param channelId - The id of the channel to fetch messages from
|
* @param channelId - The id of the channel to fetch messages from
|
||||||
* @param query - The query options for fetching messages
|
* @param query - The query options for fetching messages
|
||||||
* @param options - The options for fetching the messages
|
* @param options - The options for fetching the messages
|
||||||
@@ -299,7 +299,7 @@ export class ChannelsAPI {
|
|||||||
/**
|
/**
|
||||||
* Deletes a message
|
* Deletes a message
|
||||||
*
|
*
|
||||||
* @see {@link https://discord.com/developers/docs/resources/channel#delete-message}
|
* @see {@link https://discord.com/developers/docs/resources/message#delete-message}
|
||||||
* @param channelId - The id of the channel the message is in
|
* @param channelId - The id of the channel the message is in
|
||||||
* @param messageId - The id of the message to delete
|
* @param messageId - The id of the message to delete
|
||||||
* @param options - The options for deleting the message
|
* @param options - The options for deleting the message
|
||||||
@@ -315,7 +315,7 @@ export class ChannelsAPI {
|
|||||||
/**
|
/**
|
||||||
* Bulk deletes messages
|
* Bulk deletes messages
|
||||||
*
|
*
|
||||||
* @see {@link https://discord.com/developers/docs/resources/channel#bulk-delete-messages}
|
* @see {@link https://discord.com/developers/docs/resources/message#bulk-delete-messages}
|
||||||
* @param channelId - The id of the channel the messages are in
|
* @param channelId - The id of the channel the messages are in
|
||||||
* @param messageIds - The ids of the messages to delete
|
* @param messageIds - The ids of the messages to delete
|
||||||
* @param options - The options for deleting the messages
|
* @param options - The options for deleting the messages
|
||||||
@@ -331,7 +331,7 @@ export class ChannelsAPI {
|
|||||||
/**
|
/**
|
||||||
* Fetches a message
|
* Fetches a message
|
||||||
*
|
*
|
||||||
* @see {@link https://discord.com/developers/docs/resources/channel#get-channel-message}
|
* @see {@link https://discord.com/developers/docs/resources/message#get-channel-message}
|
||||||
* @param channelId - The id of the channel the message is in
|
* @param channelId - The id of the channel the message is in
|
||||||
* @param messageId - The id of the message to fetch
|
* @param messageId - The id of the message to fetch
|
||||||
* @param options - The options for fetching the message
|
* @param options - The options for fetching the message
|
||||||
@@ -345,7 +345,7 @@ export class ChannelsAPI {
|
|||||||
/**
|
/**
|
||||||
* Crossposts a message
|
* Crossposts a message
|
||||||
*
|
*
|
||||||
* @see {@link https://discord.com/developers/docs/resources/channel#crosspost-message}
|
* @see {@link https://discord.com/developers/docs/resources/message#crosspost-message}
|
||||||
* @param channelId - The id of the channel the message is in
|
* @param channelId - The id of the channel the message is in
|
||||||
* @param messageId - The id of the message to crosspost
|
* @param messageId - The id of the message to crosspost
|
||||||
* @param options - The options for crossposting the message
|
* @param options - The options for crossposting the message
|
||||||
@@ -452,7 +452,7 @@ export class ChannelsAPI {
|
|||||||
/**
|
/**
|
||||||
* Creates a new forum post
|
* Creates a new forum post
|
||||||
*
|
*
|
||||||
* @see {@link https://discord.com/developers/docs/resources/channel#start-thread-in-forum-channel}
|
* @see {@link https://discord.com/developers/docs/resources/channel#start-thread-in-forum-or-media-channel}
|
||||||
* @param channelId - The id of the forum channel to start the thread in
|
* @param channelId - The id of the forum channel to start the thread in
|
||||||
* @param body - The data for starting the thread
|
* @param body - The data for starting the thread
|
||||||
* @param options - The options for starting the thread
|
* @param options - The options for starting the thread
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ export class InteractionsAPI {
|
|||||||
* @param interactionId - The id of the interaction
|
* @param interactionId - The id of the interaction
|
||||||
* @param interactionToken - The token of the interaction
|
* @param interactionToken - The token of the interaction
|
||||||
* @param options - The options for sending the premium required response
|
* @param options - The options for sending the premium required response
|
||||||
* @deprecated Sending a premium-style button is the new Discord behaviour.
|
* @deprecated Sending a premium-style button is the new Discord behavior.
|
||||||
*/
|
*/
|
||||||
public async sendPremiumRequired(
|
public async sendPremiumRequired(
|
||||||
interactionId: Snowflake,
|
interactionId: Snowflake,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<p>
|
<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://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/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>
|
||||||
<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>
|
<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,8 +30,10 @@ body = """
|
|||||||
{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\
|
{{ 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.github.username %} by @{{ commit.github.username }}{%- endif %}\
|
||||||
{% if commit.breaking %}\
|
{% if commit.breaking %}\
|
||||||
{% for breakingChange in commit.footers %}\
|
{% for footer in commit.footers %}\
|
||||||
\n{% raw %} {% endraw %}- **{{ breakingChange.token }}{{ breakingChange.separator }}** {{ breakingChange.value }}\
|
{% if footer.breaking %}\
|
||||||
|
\n{% raw %} {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\
|
||||||
|
{% endif %}\
|
||||||
{% endfor %}\
|
{% endfor %}\
|
||||||
{% endif %}\
|
{% endif %}\
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@
|
|||||||
"no-void": "error",
|
"no-void": "error",
|
||||||
"no-warning-comments": "warn",
|
"no-warning-comments": "warn",
|
||||||
"prefer-promise-reject-errors": "error",
|
"prefer-promise-reject-errors": "error",
|
||||||
"require-await": "warn",
|
"require-await": "off",
|
||||||
"wrap-iife": "error",
|
"wrap-iife": "error",
|
||||||
"yoda": "error",
|
"yoda": "error",
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,148 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
# [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)
|
# [14.16.0](https://github.com/discordjs/discord.js/compare/14.15.3...14.16.0) - (2024-09-01)
|
||||||
|
|
||||||
## Bug Fixes
|
## Bug Fixes
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
<a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/v/discord.js.svg?maxAge=3600" alt="npm version" /></a>
|
<a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/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://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/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Tests status" /></a>
|
||||||
<a href="https://codecov.io/gh/discordjs/discord.js" ><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2" alt="Code coverage" /></a>
|
<a href="https://github.com/discordjs/discord.js/commits/main/packages/discord.js"><img alt="Last commit." src="https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fdiscord.js"></a>
|
||||||
|
<a href="https://codecov.io/gh/discordjs/discord.js"><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2" alt="Code coverage" /></a>
|
||||||
</p>
|
</p>
|
||||||
<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>
|
<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>
|
||||||
@@ -29,7 +30,7 @@ discord.js is a powerful [Node.js](https://nodejs.org) module that allows you to
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
**Node.js 16.11.0 or newer is required.**
|
**Node.js 18 or newer is required.**
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install discord.js
|
npm install discord.js
|
||||||
@@ -42,7 +43,6 @@ bun add discord.js
|
|||||||
|
|
||||||
- [zlib-sync](https://www.npmjs.com/package/zlib-sync) for WebSocket data compression and inflation (`npm install zlib-sync`)
|
- [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`)
|
- [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`)
|
- [@discordjs/voice](https://www.npmjs.com/package/@discordjs/voice) for interacting with the Discord Voice API (`npm install @discordjs/voice`)
|
||||||
|
|
||||||
## Example usage
|
## Example usage
|
||||||
|
|||||||
@@ -30,8 +30,10 @@ body = """
|
|||||||
{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\
|
{{ 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.github.username %} by @{{ commit.github.username }}{%- endif %}\
|
||||||
{% if commit.breaking %}\
|
{% if commit.breaking %}\
|
||||||
{% for breakingChange in commit.footers %}\
|
{% for footer in commit.footers %}\
|
||||||
\n{% raw %} {% endraw %}- **{{ breakingChange.token }}{{ breakingChange.separator }}** {{ breakingChange.value }}\
|
{% if footer.breaking %}\
|
||||||
|
\n{% raw %} {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\
|
||||||
|
{% endif %}\
|
||||||
{% endfor %}\
|
{% endfor %}\
|
||||||
{% endif %}\
|
{% endif %}\
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@@ -67,8 +69,7 @@ commit_parsers = [
|
|||||||
{ body = ".*security", group = "Security"},
|
{ body = ".*security", group = "Security"},
|
||||||
]
|
]
|
||||||
filter_commits = true
|
filter_commits = true
|
||||||
tag_pattern = "[0-9]*"
|
tag_pattern = "^[0-9]+"
|
||||||
skip_tags = "v[0-9]*|@discordjs*"
|
|
||||||
ignore_tags = ""
|
ignore_tags = ""
|
||||||
topo_order = false
|
topo_order = false
|
||||||
sort_commits = "newest"
|
sort_commits = "newest"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"name": "discord.js",
|
"name": "discord.js",
|
||||||
"version": "14.16.0",
|
"version": "14.18.0",
|
||||||
"description": "A powerful library for interacting with the Discord API",
|
"description": "A powerful library for interacting with the Discord API",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "pnpm run docs:test && pnpm run test:typescript",
|
"test": "pnpm run docs:test && pnpm run test:typescript",
|
||||||
@@ -65,14 +65,14 @@
|
|||||||
"homepage": "https://discord.js.org",
|
"homepage": "https://discord.js.org",
|
||||||
"funding": "https://github.com/discordjs/discord.js?sponsor",
|
"funding": "https://github.com/discordjs/discord.js?sponsor",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discordjs/builders": "workspace:^",
|
"@discordjs/builders": "^1.10.1",
|
||||||
"@discordjs/collection": "1.5.3",
|
"@discordjs/collection": "1.5.3",
|
||||||
"@discordjs/formatters": "workspace:^",
|
"@discordjs/formatters": "^0.6.0",
|
||||||
"@discordjs/rest": "workspace:^",
|
"@discordjs/rest": "workspace:^",
|
||||||
"@discordjs/util": "workspace:^",
|
"@discordjs/util": "workspace:^",
|
||||||
"@discordjs/ws": "1.1.1",
|
"@discordjs/ws": "^1.2.1",
|
||||||
"@sapphire/snowflake": "3.5.3",
|
"@sapphire/snowflake": "3.5.3",
|
||||||
"discord-api-types": "^0.38.1",
|
"discord-api-types": "^0.37.119",
|
||||||
"fast-deep-equal": "3.1.3",
|
"fast-deep-equal": "3.1.3",
|
||||||
"lodash.snakecase": "4.1.1",
|
"lodash.snakecase": "4.1.1",
|
||||||
"tslib": "^2.6.3",
|
"tslib": "^2.6.3",
|
||||||
@@ -98,7 +98,7 @@
|
|||||||
"typescript": "~5.5.4"
|
"typescript": "~5.5.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16.11.0"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"provenance": true
|
"provenance": true
|
||||||
|
|||||||
@@ -107,20 +107,20 @@ class Client extends BaseClient {
|
|||||||
: null;
|
: null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All of the {@link User} objects that have been cached at any point, mapped by their ids
|
* The user manager of this client
|
||||||
* @type {UserManager}
|
* @type {UserManager}
|
||||||
*/
|
*/
|
||||||
this.users = new UserManager(this);
|
this.users = new UserManager(this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All of the guilds the client is currently handling, mapped by their ids -
|
* A manager of all the guilds the client is currently handling -
|
||||||
* as long as sharding isn't being used, this will be *every* guild the bot is a member of
|
* as long as sharding isn't being used, this will be *every* guild the bot is a member of
|
||||||
* @type {GuildManager}
|
* @type {GuildManager}
|
||||||
*/
|
*/
|
||||||
this.guilds = new GuildManager(this);
|
this.guilds = new GuildManager(this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All of the {@link BaseChannel}s that the client is currently handling, mapped by their ids -
|
* All of the {@link BaseChannel}s that the client is currently handling -
|
||||||
* as long as sharding isn't being used, this will be *every* channel in *every* guild the bot
|
* 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
|
* 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.
|
* in the Manager without their explicit fetching or use.
|
||||||
@@ -174,7 +174,7 @@ class Client extends BaseClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All custom emojis that the client has access to, mapped by their ids
|
* A manager of all the custom emojis that the client has access to
|
||||||
* @type {BaseGuildEmojiManager}
|
* @type {BaseGuildEmojiManager}
|
||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -111,6 +111,10 @@ class GenericAction {
|
|||||||
getThreadMember(id, manager) {
|
getThreadMember(id, manager) {
|
||||||
return this.getPayload({ user_id: id }, manager, id, Partials.ThreadMember, false);
|
return this.getPayload({ user_id: id }, manager, id, Partials.ThreadMember, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spreadInjectedData(data) {
|
||||||
|
return Object.fromEntries(Object.getOwnPropertySymbols(data).map(symbol => [symbol, data[symbol]]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = GenericAction;
|
module.exports = GenericAction;
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ const Events = require('../../util/Events');
|
|||||||
class MessageCreateAction extends Action {
|
class MessageCreateAction extends Action {
|
||||||
handle(data) {
|
handle(data) {
|
||||||
const client = this.client;
|
const client = this.client;
|
||||||
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id, author: data.author });
|
const channel = this.getChannel({
|
||||||
|
id: data.channel_id,
|
||||||
|
author: data.author,
|
||||||
|
...('guild_id' in data && { guild_id: data.guild_id }),
|
||||||
|
});
|
||||||
if (channel) {
|
if (channel) {
|
||||||
if (!channel.isTextBased()) return {};
|
if (!channel.isTextBased()) return {};
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const Events = require('../../util/Events');
|
|||||||
class MessageDeleteAction extends Action {
|
class MessageDeleteAction extends Action {
|
||||||
handle(data) {
|
handle(data) {
|
||||||
const client = this.client;
|
const client = this.client;
|
||||||
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id });
|
const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });
|
||||||
let message;
|
let message;
|
||||||
if (channel) {
|
if (channel) {
|
||||||
if (!channel.isTextBased()) return {};
|
if (!channel.isTextBased()) return {};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ const Events = require('../../util/Events');
|
|||||||
|
|
||||||
class MessagePollVoteAddAction extends Action {
|
class MessagePollVoteAddAction extends Action {
|
||||||
handle(data) {
|
handle(data) {
|
||||||
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id });
|
const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });
|
||||||
if (!channel?.isTextBased()) return false;
|
if (!channel?.isTextBased()) return false;
|
||||||
|
|
||||||
const message = this.getMessage(data, channel);
|
const message = this.getMessage(data, channel);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ const Events = require('../../util/Events');
|
|||||||
|
|
||||||
class MessagePollVoteRemoveAction extends Action {
|
class MessagePollVoteRemoveAction extends Action {
|
||||||
handle(data) {
|
handle(data) {
|
||||||
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id });
|
const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });
|
||||||
if (!channel?.isTextBased()) return false;
|
if (!channel?.isTextBased()) return false;
|
||||||
|
|
||||||
const message = this.getMessage(data, channel);
|
const message = this.getMessage(data, channel);
|
||||||
|
|||||||
@@ -23,7 +23,13 @@ class MessageReactionAdd extends Action {
|
|||||||
if (!user) return false;
|
if (!user) return false;
|
||||||
|
|
||||||
// Verify channel
|
// Verify channel
|
||||||
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id, user_id: data.user_id });
|
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),
|
||||||
|
});
|
||||||
|
|
||||||
if (!channel?.isTextBased()) return false;
|
if (!channel?.isTextBased()) return false;
|
||||||
|
|
||||||
// Verify message
|
// Verify message
|
||||||
@@ -45,6 +51,7 @@ class MessageReactionAdd extends Action {
|
|||||||
/**
|
/**
|
||||||
* Provides additional information about altered reaction
|
* Provides additional information about altered reaction
|
||||||
* @typedef {Object} MessageReactionEventDetails
|
* @typedef {Object} MessageReactionEventDetails
|
||||||
|
* @property {ReactionType} type The type of the reaction
|
||||||
* @property {boolean} burst Determines whether a super reaction was used
|
* @property {boolean} burst Determines whether a super reaction was used
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
@@ -54,7 +61,7 @@ class MessageReactionAdd extends Action {
|
|||||||
* @param {User} user The user that applied the guild or reaction emoji
|
* @param {User} user The user that applied the guild or reaction emoji
|
||||||
* @param {MessageReactionEventDetails} details Details of adding the reaction
|
* @param {MessageReactionEventDetails} details Details of adding the reaction
|
||||||
*/
|
*/
|
||||||
this.client.emit(Events.MessageReactionAdd, reaction, user, { burst: data.burst });
|
this.client.emit(Events.MessageReactionAdd, reaction, user, { type: data.type, burst: data.burst });
|
||||||
|
|
||||||
return { message, reaction, user };
|
return { message, reaction, user };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,11 @@ class MessageReactionRemove extends Action {
|
|||||||
if (!user) return false;
|
if (!user) return false;
|
||||||
|
|
||||||
// Verify channel
|
// Verify channel
|
||||||
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id, user_id: data.user_id });
|
const channel = this.getChannel({
|
||||||
|
id: data.channel_id,
|
||||||
|
...('guild_id' in data && { guild_id: data.guild_id }),
|
||||||
|
user_id: data.user_id,
|
||||||
|
});
|
||||||
if (!channel?.isTextBased()) return false;
|
if (!channel?.isTextBased()) return false;
|
||||||
|
|
||||||
// Verify message
|
// Verify message
|
||||||
@@ -37,7 +41,7 @@ class MessageReactionRemove extends Action {
|
|||||||
* @param {User} user The user whose emoji or reaction emoji was removed
|
* @param {User} user The user whose emoji or reaction emoji was removed
|
||||||
* @param {MessageReactionEventDetails} details Details of removing the reaction
|
* @param {MessageReactionEventDetails} details Details of removing the reaction
|
||||||
*/
|
*/
|
||||||
this.client.emit(Events.MessageReactionRemove, reaction, user, { burst: data.burst });
|
this.client.emit(Events.MessageReactionRemove, reaction, user, { type: data.type, burst: data.burst });
|
||||||
|
|
||||||
return { message, reaction, user };
|
return { message, reaction, user };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const Events = require('../../util/Events');
|
|||||||
class MessageReactionRemoveAll extends Action {
|
class MessageReactionRemoveAll extends Action {
|
||||||
handle(data) {
|
handle(data) {
|
||||||
// Verify channel
|
// Verify channel
|
||||||
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id });
|
const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });
|
||||||
if (!channel?.isTextBased()) return false;
|
if (!channel?.isTextBased()) return false;
|
||||||
|
|
||||||
// Verify message
|
// Verify message
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ const Events = require('../../util/Events');
|
|||||||
|
|
||||||
class MessageReactionRemoveEmoji extends Action {
|
class MessageReactionRemoveEmoji extends Action {
|
||||||
handle(data) {
|
handle(data) {
|
||||||
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id });
|
const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });
|
||||||
if (!channel?.isTextBased()) return false;
|
if (!channel?.isTextBased()) return false;
|
||||||
|
|
||||||
const message = this.getMessage(data, channel);
|
const message = this.getMessage(data, channel);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const Action = require('./Action');
|
|||||||
|
|
||||||
class MessageUpdateAction extends Action {
|
class MessageUpdateAction extends Action {
|
||||||
handle(data) {
|
handle(data) {
|
||||||
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id });
|
const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });
|
||||||
if (channel) {
|
if (channel) {
|
||||||
if (!channel.isTextBased()) return {};
|
if (!channel.isTextBased()) return {};
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,14 @@
|
|||||||
|
|
||||||
const Action = require('./Action');
|
const Action = require('./Action');
|
||||||
const Events = require('../../util/Events');
|
const Events = require('../../util/Events');
|
||||||
|
const Partials = require('../../util/Partials');
|
||||||
|
|
||||||
class PresenceUpdateAction extends Action {
|
class PresenceUpdateAction extends Action {
|
||||||
handle(data) {
|
handle(data) {
|
||||||
let user = this.client.users.cache.get(data.user.id);
|
let user = this.client.users.cache.get(data.user.id);
|
||||||
if (!user && data.user.username) user = this.client.users._add(data.user);
|
if (!user && ('username' in data.user || this.client.options.partials.includes(Partials.User))) {
|
||||||
|
user = this.client.users._add(data.user);
|
||||||
|
}
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
|
|
||||||
if (data.user.username) {
|
if (data.user.username) {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class ThreadListSyncAction extends Action {
|
|||||||
|
|
||||||
if (data.channel_ids) {
|
if (data.channel_ids) {
|
||||||
for (const id of data.channel_ids) {
|
for (const id of data.channel_ids) {
|
||||||
const channel = client.channels.resolve(id);
|
const channel = client.channels.cache.get(id);
|
||||||
if (channel) this.removeStale(channel);
|
if (channel) this.removeStale(channel);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const Events = require('../../util/Events');
|
|||||||
|
|
||||||
class TypingStart extends Action {
|
class TypingStart extends Action {
|
||||||
handle(data) {
|
handle(data) {
|
||||||
const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id });
|
const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });
|
||||||
if (!channel) return;
|
if (!channel) return;
|
||||||
|
|
||||||
if (!channel.isTextBased()) {
|
if (!channel.isTextBased()) {
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
'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);
|
||||||
|
};
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
'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);
|
||||||
|
};
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
'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);
|
||||||
|
};
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
'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));
|
||||||
|
};
|
||||||
@@ -53,6 +53,9 @@ const handlers = Object.fromEntries([
|
|||||||
['STAGE_INSTANCE_CREATE', require('./STAGE_INSTANCE_CREATE')],
|
['STAGE_INSTANCE_CREATE', require('./STAGE_INSTANCE_CREATE')],
|
||||||
['STAGE_INSTANCE_DELETE', require('./STAGE_INSTANCE_DELETE')],
|
['STAGE_INSTANCE_DELETE', require('./STAGE_INSTANCE_DELETE')],
|
||||||
['STAGE_INSTANCE_UPDATE', require('./STAGE_INSTANCE_UPDATE')],
|
['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_CREATE', require('./THREAD_CREATE')],
|
||||||
['THREAD_DELETE', require('./THREAD_DELETE')],
|
['THREAD_DELETE', require('./THREAD_DELETE')],
|
||||||
['THREAD_LIST_SYNC', require('./THREAD_LIST_SYNC')],
|
['THREAD_LIST_SYNC', require('./THREAD_LIST_SYNC')],
|
||||||
@@ -61,6 +64,7 @@ const handlers = Object.fromEntries([
|
|||||||
['THREAD_UPDATE', require('./THREAD_UPDATE')],
|
['THREAD_UPDATE', require('./THREAD_UPDATE')],
|
||||||
['TYPING_START', require('./TYPING_START')],
|
['TYPING_START', require('./TYPING_START')],
|
||||||
['USER_UPDATE', require('./USER_UPDATE')],
|
['USER_UPDATE', require('./USER_UPDATE')],
|
||||||
|
['VOICE_CHANNEL_EFFECT_SEND', require('./VOICE_CHANNEL_EFFECT_SEND')],
|
||||||
['VOICE_SERVER_UPDATE', require('./VOICE_SERVER_UPDATE')],
|
['VOICE_SERVER_UPDATE', require('./VOICE_SERVER_UPDATE')],
|
||||||
['VOICE_STATE_UPDATE', require('./VOICE_STATE_UPDATE')],
|
['VOICE_STATE_UPDATE', require('./VOICE_STATE_UPDATE')],
|
||||||
['WEBHOOKS_UPDATE', require('./WEBHOOKS_UPDATE')],
|
['WEBHOOKS_UPDATE', require('./WEBHOOKS_UPDATE')],
|
||||||
|
|||||||
@@ -95,7 +95,8 @@ const Messages = {
|
|||||||
[DjsErrorCodes.ChannelNotCached]: 'Could not find the channel where this message came from in the cache!',
|
[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.StageChannelResolve]: 'Could not resolve channel to a stage channel.',
|
||||||
[DjsErrorCodes.GuildScheduledEventResolve]: 'Could not resolve the guild scheduled event.',
|
[DjsErrorCodes.GuildScheduledEventResolve]: 'Could not resolve the guild scheduled event.',
|
||||||
[DjsErrorCodes.FetchOwnerId]: type => `Couldn't resolve the ${type} ownerId to fetch the ${type} member.`,
|
[DjsErrorCodes.FetchOwnerId]: type =>
|
||||||
|
`Couldn't resolve the ${type} ownerId to fetch the ${type} ${type === 'group DM' ? 'owner' : 'member'}.`,
|
||||||
|
|
||||||
[DjsErrorCodes.InvalidType]: (name, expected, an = false) => `Supplied ${name} is not a${an ? 'n' : ''} ${expected}.`,
|
[DjsErrorCodes.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}`,
|
[DjsErrorCodes.InvalidElement]: (type, name, elem) => `Supplied ${type} ${name} includes an invalid element: ${elem}`,
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ exports.ChannelFlagsBitField = require('./util/ChannelFlagsBitField');
|
|||||||
exports.Collection = require('@discordjs/collection').Collection;
|
exports.Collection = require('@discordjs/collection').Collection;
|
||||||
exports.Constants = require('./util/Constants');
|
exports.Constants = require('./util/Constants');
|
||||||
exports.Colors = require('./util/Colors');
|
exports.Colors = require('./util/Colors');
|
||||||
__exportStar(require('./util/DataResolver.js'), exports);
|
|
||||||
exports.Events = require('./util/Events');
|
exports.Events = require('./util/Events');
|
||||||
exports.Formatters = require('./util/Formatters');
|
exports.Formatters = require('./util/Formatters');
|
||||||
exports.GuildMemberFlagsBitField = require('./util/GuildMemberFlagsBitField').GuildMemberFlagsBitField;
|
exports.GuildMemberFlagsBitField = require('./util/GuildMemberFlagsBitField').GuildMemberFlagsBitField;
|
||||||
@@ -85,6 +84,7 @@ exports.ReactionManager = require('./managers/ReactionManager');
|
|||||||
exports.ReactionUserManager = require('./managers/ReactionUserManager');
|
exports.ReactionUserManager = require('./managers/ReactionUserManager');
|
||||||
exports.RoleManager = require('./managers/RoleManager');
|
exports.RoleManager = require('./managers/RoleManager');
|
||||||
exports.StageInstanceManager = require('./managers/StageInstanceManager');
|
exports.StageInstanceManager = require('./managers/StageInstanceManager');
|
||||||
|
exports.SubscriptionManager = require('./managers/SubscriptionManager').SubscriptionManager;
|
||||||
exports.ThreadManager = require('./managers/ThreadManager');
|
exports.ThreadManager = require('./managers/ThreadManager');
|
||||||
exports.ThreadMemberManager = require('./managers/ThreadMemberManager');
|
exports.ThreadMemberManager = require('./managers/ThreadMemberManager');
|
||||||
exports.UserManager = require('./managers/UserManager');
|
exports.UserManager = require('./managers/UserManager');
|
||||||
@@ -146,6 +146,9 @@ exports.GuildScheduledEvent = require('./structures/GuildScheduledEvent').GuildS
|
|||||||
exports.GuildTemplate = require('./structures/GuildTemplate');
|
exports.GuildTemplate = require('./structures/GuildTemplate');
|
||||||
exports.Integration = require('./structures/Integration');
|
exports.Integration = require('./structures/Integration');
|
||||||
exports.IntegrationApplication = require('./structures/IntegrationApplication');
|
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.BaseInteraction = require('./structures/BaseInteraction');
|
||||||
exports.InteractionCollector = require('./structures/InteractionCollector');
|
exports.InteractionCollector = require('./structures/InteractionCollector');
|
||||||
exports.InteractionResponse = require('./structures/InteractionResponse');
|
exports.InteractionResponse = require('./structures/InteractionResponse');
|
||||||
@@ -202,6 +205,7 @@ exports.SKU = require('./structures/SKU').SKU;
|
|||||||
exports.StringSelectMenuOptionBuilder = require('./structures/StringSelectMenuOptionBuilder');
|
exports.StringSelectMenuOptionBuilder = require('./structures/StringSelectMenuOptionBuilder');
|
||||||
exports.StageChannel = require('./structures/StageChannel');
|
exports.StageChannel = require('./structures/StageChannel');
|
||||||
exports.StageInstance = require('./structures/StageInstance').StageInstance;
|
exports.StageInstance = require('./structures/StageInstance').StageInstance;
|
||||||
|
exports.Subscription = require('./structures/Subscription').Subscription;
|
||||||
exports.Sticker = require('./structures/Sticker').Sticker;
|
exports.Sticker = require('./structures/Sticker').Sticker;
|
||||||
exports.StickerPack = require('./structures/StickerPack');
|
exports.StickerPack = require('./structures/StickerPack');
|
||||||
exports.Team = require('./structures/Team');
|
exports.Team = require('./structures/Team');
|
||||||
@@ -215,6 +219,7 @@ exports.ThreadOnlyChannel = require('./structures/ThreadOnlyChannel');
|
|||||||
exports.Typing = require('./structures/Typing');
|
exports.Typing = require('./structures/Typing');
|
||||||
exports.User = require('./structures/User');
|
exports.User = require('./structures/User');
|
||||||
exports.UserContextMenuCommandInteraction = require('./structures/UserContextMenuCommandInteraction');
|
exports.UserContextMenuCommandInteraction = require('./structures/UserContextMenuCommandInteraction');
|
||||||
|
exports.VoiceChannelEffect = require('./structures/VoiceChannelEffect');
|
||||||
exports.VoiceChannel = require('./structures/VoiceChannel');
|
exports.VoiceChannel = require('./structures/VoiceChannel');
|
||||||
exports.VoiceRegion = require('./structures/VoiceRegion');
|
exports.VoiceRegion = require('./structures/VoiceRegion');
|
||||||
exports.VoiceState = require('./structures/VoiceState');
|
exports.VoiceState = require('./structures/VoiceState');
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class ApplicationCommandManager extends CachedManager {
|
|||||||
* Options used to fetch Application Commands from Discord
|
* Options used to fetch Application Commands from Discord
|
||||||
* @typedef {BaseFetchOptions} FetchApplicationCommandOptions
|
* @typedef {BaseFetchOptions} FetchApplicationCommandOptions
|
||||||
* @property {Snowflake} [guildId] The guild's id to fetch commands for, for when the guild is not cached
|
* @property {Snowflake} [guildId] The guild's id to fetch commands for, for when the guild is not cached
|
||||||
* @property {LocaleString} [locale] The locale to use when fetching this command
|
* @property {Locale} [locale] The locale to use when fetching this command
|
||||||
* @property {boolean} [withLocalizations] Whether to fetch all localization data
|
* @property {boolean} [withLocalizations] Whether to fetch all localization data
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -65,12 +65,12 @@ class ApplicationEmojiManager extends CachedManager {
|
|||||||
* @returns {Promise<ApplicationEmoji|Collection<Snowflake, ApplicationEmoji>>}
|
* @returns {Promise<ApplicationEmoji|Collection<Snowflake, ApplicationEmoji>>}
|
||||||
* @example
|
* @example
|
||||||
* // Fetch all emojis from the application
|
* // Fetch all emojis from the application
|
||||||
* message.application.emojis.fetch()
|
* application.emojis.fetch()
|
||||||
* .then(emojis => console.log(`There are ${emojis.size} emojis.`))
|
* .then(emojis => console.log(`There are ${emojis.size} emojis.`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
* @example
|
* @example
|
||||||
* // Fetch a single emoji
|
* // Fetch a single emoji
|
||||||
* message.application.emojis.fetch('222078108977594368')
|
* application.emojis.fetch('222078108977594368')
|
||||||
* .then(emoji => console.log(`The emoji name is: ${emoji.name}`))
|
* .then(emoji => console.log(`The emoji name is: ${emoji.name}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const CachedManager = require('./CachedManager');
|
const CachedManager = require('./CachedManager');
|
||||||
|
const ApplicationEmoji = require('../structures/ApplicationEmoji');
|
||||||
const GuildEmoji = require('../structures/GuildEmoji');
|
const GuildEmoji = require('../structures/GuildEmoji');
|
||||||
const ReactionEmoji = require('../structures/ReactionEmoji');
|
const ReactionEmoji = require('../structures/ReactionEmoji');
|
||||||
const { parseEmoji } = require('../util/Util');
|
const { parseEmoji } = require('../util/Util');
|
||||||
@@ -25,7 +26,8 @@ class BaseGuildEmojiManager extends CachedManager {
|
|||||||
* * A Snowflake
|
* * A Snowflake
|
||||||
* * A GuildEmoji object
|
* * A GuildEmoji object
|
||||||
* * A ReactionEmoji object
|
* * A ReactionEmoji object
|
||||||
* @typedef {Snowflake|GuildEmoji|ReactionEmoji} EmojiResolvable
|
* * An ApplicationEmoji object
|
||||||
|
* @typedef {Snowflake|GuildEmoji|ReactionEmoji|ApplicationEmoji} EmojiResolvable
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,7 +36,8 @@ class BaseGuildEmojiManager extends CachedManager {
|
|||||||
* @returns {?GuildEmoji}
|
* @returns {?GuildEmoji}
|
||||||
*/
|
*/
|
||||||
resolve(emoji) {
|
resolve(emoji) {
|
||||||
if (emoji instanceof ReactionEmoji) return super.resolve(emoji.id);
|
if (emoji instanceof ReactionEmoji) return this.cache.get(emoji.id) ?? null;
|
||||||
|
if (emoji instanceof ApplicationEmoji) return this.cache.get(emoji.id) ?? null;
|
||||||
return super.resolve(emoji);
|
return super.resolve(emoji);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,6 +48,7 @@ class BaseGuildEmojiManager extends CachedManager {
|
|||||||
*/
|
*/
|
||||||
resolveId(emoji) {
|
resolveId(emoji) {
|
||||||
if (emoji instanceof ReactionEmoji) return emoji.id;
|
if (emoji instanceof ReactionEmoji) return emoji.id;
|
||||||
|
if (emoji instanceof ApplicationEmoji) return emoji.id;
|
||||||
return super.resolveId(emoji);
|
return super.resolveId(emoji);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,6 +69,7 @@ class BaseGuildEmojiManager extends CachedManager {
|
|||||||
const emojiResolvable = this.resolve(emoji);
|
const emojiResolvable = this.resolve(emoji);
|
||||||
if (emojiResolvable) return emojiResolvable.identifier;
|
if (emojiResolvable) return emojiResolvable.identifier;
|
||||||
if (emoji instanceof ReactionEmoji) return emoji.identifier;
|
if (emoji instanceof ReactionEmoji) return emoji.identifier;
|
||||||
|
if (emoji instanceof ApplicationEmoji) return emoji.identifier;
|
||||||
if (typeof emoji === 'string') {
|
if (typeof emoji === 'string') {
|
||||||
const res = parseEmoji(emoji);
|
const res = parseEmoji(emoji);
|
||||||
if (res?.name.length) {
|
if (res?.name.length) {
|
||||||
|
|||||||
@@ -37,6 +37,12 @@ class EntitlementManager extends CachedManager {
|
|||||||
* @typedef {SKU|Snowflake} SKUResolvable
|
* @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
|
* Options used to fetch entitlements
|
||||||
* @typedef {Object} FetchEntitlementsOptions
|
* @typedef {Object} FetchEntitlementsOptions
|
||||||
@@ -45,6 +51,7 @@ class EntitlementManager extends CachedManager {
|
|||||||
* @property {UserResolvable} [user] The user to fetch entitlements for
|
* @property {UserResolvable} [user] The user to fetch entitlements for
|
||||||
* @property {SKUResolvable[]} [skus] The SKUs to fetch entitlements for
|
* @property {SKUResolvable[]} [skus] The SKUs to fetch entitlements for
|
||||||
* @property {boolean} [excludeEnded] Whether to exclude ended entitlements
|
* @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 {boolean} [cache=true] Whether to cache the fetched entitlements
|
||||||
* @property {Snowflake} [before] Consider only entitlements before this entitlement id
|
* @property {Snowflake} [before] Consider only entitlements before this entitlement id
|
||||||
* @property {Snowflake} [after] Consider only entitlements after this entitlement id
|
* @property {Snowflake} [after] Consider only entitlements after this entitlement id
|
||||||
@@ -53,21 +60,49 @@ class EntitlementManager extends CachedManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches entitlements for this application
|
* Fetches entitlements for this application
|
||||||
* @param {FetchEntitlementsOptions} [options={}] Options for fetching the entitlements
|
* @param {EntitlementResolvable|FetchEntitlementOptions|FetchEntitlementsOptions} [options]
|
||||||
* @returns {Promise<Collection<Snowflake, Entitlement>>}
|
* Options for fetching the entitlements
|
||||||
|
* @returns {Promise<Entitlement|Collection<Snowflake, Entitlement>>}
|
||||||
*/
|
*/
|
||||||
async fetch({ limit, guild, user, skus, excludeEnded, cache = true, before, after } = {}) {
|
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 } = {}) {
|
||||||
const query = makeURLSearchParams({
|
const query = makeURLSearchParams({
|
||||||
limit,
|
limit,
|
||||||
guild_id: guild && this.client.guilds.resolveId(guild),
|
guild_id: guild && this.client.guilds.resolveId(guild),
|
||||||
user_id: user && this.client.users.resolveId(user),
|
user_id: user && this.client.users.resolveId(user),
|
||||||
sku_ids: skus?.map(sku => resolveSKUId(sku)).join(','),
|
sku_ids: skus?.map(sku => resolveSKUId(sku)).join(','),
|
||||||
exclude_ended: excludeEnded,
|
exclude_ended: excludeEnded,
|
||||||
|
exclude_deleted: excludeDeleted,
|
||||||
before,
|
before,
|
||||||
after,
|
after,
|
||||||
});
|
});
|
||||||
|
|
||||||
const entitlements = await this.client.rest.get(Routes.entitlements(this.client.application.id), { query });
|
const entitlements = await this.client.rest.get(Routes.entitlements(this.client.application.id), { query });
|
||||||
|
|
||||||
return entitlements.reduce(
|
return entitlements.reduce(
|
||||||
(coll, entitlement) => coll.set(entitlement.id, this._add(entitlement, cache)),
|
(coll, entitlement) => coll.set(entitlement.id, this._add(entitlement, cache)),
|
||||||
new Collection(),
|
new Collection(),
|
||||||
|
|||||||
@@ -97,14 +97,14 @@ class GuildBanManager extends CachedManager {
|
|||||||
* .then(console.log)
|
* .then(console.log)
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
fetch(options) {
|
async fetch(options) {
|
||||||
if (!options) return this._fetchMany();
|
if (!options) return this._fetchMany();
|
||||||
const { user, cache, force, limit, before, after } = options;
|
const { user, cache, force, limit, before, after } = options;
|
||||||
const resolvedUser = this.client.users.resolveId(user ?? options);
|
const resolvedUser = this.client.users.resolveId(user ?? options);
|
||||||
if (resolvedUser) return this._fetchSingle({ user: resolvedUser, cache, force });
|
if (resolvedUser) return this._fetchSingle({ user: resolvedUser, cache, force });
|
||||||
|
|
||||||
if (!before && !after && !limit && cache === undefined) {
|
if (!before && !after && !limit && cache === undefined) {
|
||||||
return Promise.reject(new DiscordjsError(ErrorCodes.FetchBanResolveId));
|
throw new DiscordjsError(ErrorCodes.FetchBanResolveId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._fetchMany(options);
|
return this._fetchMany(options);
|
||||||
@@ -175,7 +175,7 @@ class GuildBanManager extends CachedManager {
|
|||||||
reason: options.reason,
|
reason: options.reason,
|
||||||
});
|
});
|
||||||
if (user instanceof GuildMember) return user;
|
if (user instanceof GuildMember) return user;
|
||||||
const _user = this.client.users.resolve(id);
|
const _user = this.client.users.cache.get(id);
|
||||||
if (_user) {
|
if (_user) {
|
||||||
return this.guild.members.resolve(_user) ?? _user;
|
return this.guild.members.resolve(_user) ?? _user;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ class GuildChannelManager extends CachedManager {
|
|||||||
* @returns {?(GuildChannel|ThreadChannel)}
|
* @returns {?(GuildChannel|ThreadChannel)}
|
||||||
*/
|
*/
|
||||||
resolve(channel) {
|
resolve(channel) {
|
||||||
if (channel instanceof ThreadChannel) return super.resolve(channel.id);
|
if (channel instanceof ThreadChannel) return this.cache.get(channel.id) ?? null;
|
||||||
return super.resolve(channel);
|
return super.resolve(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,7 +287,7 @@ class GuildChannelManager extends CachedManager {
|
|||||||
const resolvedChannel = this.resolve(channel);
|
const resolvedChannel = this.resolve(channel);
|
||||||
if (!resolvedChannel) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable');
|
if (!resolvedChannel) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable');
|
||||||
|
|
||||||
const parent = options.parent && this.client.channels.resolveId(options.parent);
|
const parentId = options.parent && this.client.channels.resolveId(options.parent);
|
||||||
|
|
||||||
if (options.position !== undefined) {
|
if (options.position !== undefined) {
|
||||||
await this.setPosition(resolvedChannel, options.position, { position: options.position, reason: options.reason });
|
await this.setPosition(resolvedChannel, options.position, { position: options.position, reason: options.reason });
|
||||||
@@ -298,8 +298,8 @@ class GuildChannelManager extends CachedManager {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (options.lockPermissions) {
|
if (options.lockPermissions) {
|
||||||
if (parent) {
|
if (parentId) {
|
||||||
const newParent = this.guild.channels.resolve(parent);
|
const newParent = this.cache.get(parentId);
|
||||||
if (newParent?.type === ChannelType.GuildCategory) {
|
if (newParent?.type === ChannelType.GuildCategory) {
|
||||||
permission_overwrites = newParent.permissionOverwrites.cache.map(overwrite =>
|
permission_overwrites = newParent.permissionOverwrites.cache.map(overwrite =>
|
||||||
PermissionOverwrites.resolve(overwrite, this.guild),
|
PermissionOverwrites.resolve(overwrite, this.guild),
|
||||||
@@ -322,7 +322,7 @@ class GuildChannelManager extends CachedManager {
|
|||||||
user_limit: options.userLimit,
|
user_limit: options.userLimit,
|
||||||
rtc_region: options.rtcRegion,
|
rtc_region: options.rtcRegion,
|
||||||
video_quality_mode: options.videoQualityMode,
|
video_quality_mode: options.videoQualityMode,
|
||||||
parent_id: parent,
|
parent_id: parentId,
|
||||||
lock_permissions: options.lockPermissions,
|
lock_permissions: options.lockPermissions,
|
||||||
rate_limit_per_user: options.rateLimitPerUser,
|
rate_limit_per_user: options.rateLimitPerUser,
|
||||||
default_auto_archive_duration: options.defaultAutoArchiveDuration,
|
default_auto_archive_duration: options.defaultAutoArchiveDuration,
|
||||||
|
|||||||
@@ -39,14 +39,14 @@ class GuildEmojiRoleManager extends DataManager {
|
|||||||
* @param {RoleResolvable|RoleResolvable[]|Collection<Snowflake, Role>} roleOrRoles The role or roles to add
|
* @param {RoleResolvable|RoleResolvable[]|Collection<Snowflake, Role>} roleOrRoles The role or roles to add
|
||||||
* @returns {Promise<GuildEmoji>}
|
* @returns {Promise<GuildEmoji>}
|
||||||
*/
|
*/
|
||||||
add(roleOrRoles) {
|
async add(roleOrRoles) {
|
||||||
if (!Array.isArray(roleOrRoles) && !(roleOrRoles instanceof Collection)) roleOrRoles = [roleOrRoles];
|
if (!Array.isArray(roleOrRoles) && !(roleOrRoles instanceof Collection)) roleOrRoles = [roleOrRoles];
|
||||||
|
|
||||||
const resolvedRoles = [];
|
const resolvedRoles = [];
|
||||||
for (const role of roleOrRoles.values()) {
|
for (const role of roleOrRoles.values()) {
|
||||||
const resolvedRole = this.guild.roles.resolveId(role);
|
const resolvedRole = this.guild.roles.resolveId(role);
|
||||||
if (!resolvedRole) {
|
if (!resolvedRole) {
|
||||||
return Promise.reject(new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'roles', role));
|
throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'roles', role);
|
||||||
}
|
}
|
||||||
resolvedRoles.push(resolvedRole);
|
resolvedRoles.push(resolvedRole);
|
||||||
}
|
}
|
||||||
@@ -60,14 +60,14 @@ class GuildEmojiRoleManager extends DataManager {
|
|||||||
* @param {RoleResolvable|RoleResolvable[]|Collection<Snowflake, Role>} roleOrRoles The role or roles to remove
|
* @param {RoleResolvable|RoleResolvable[]|Collection<Snowflake, Role>} roleOrRoles The role or roles to remove
|
||||||
* @returns {Promise<GuildEmoji>}
|
* @returns {Promise<GuildEmoji>}
|
||||||
*/
|
*/
|
||||||
remove(roleOrRoles) {
|
async remove(roleOrRoles) {
|
||||||
if (!Array.isArray(roleOrRoles) && !(roleOrRoles instanceof Collection)) roleOrRoles = [roleOrRoles];
|
if (!Array.isArray(roleOrRoles) && !(roleOrRoles instanceof Collection)) roleOrRoles = [roleOrRoles];
|
||||||
|
|
||||||
const resolvedRoleIds = [];
|
const resolvedRoleIds = [];
|
||||||
for (const role of roleOrRoles.values()) {
|
for (const role of roleOrRoles.values()) {
|
||||||
const roleId = this.guild.roles.resolveId(role);
|
const roleId = this.guild.roles.resolveId(role);
|
||||||
if (!roleId) {
|
if (!roleId) {
|
||||||
return Promise.reject(new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'roles', role));
|
throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'roles', role);
|
||||||
}
|
}
|
||||||
resolvedRoleIds.push(roleId);
|
resolvedRoleIds.push(roleId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,22 +121,22 @@ class GuildInviteManager extends CachedManager {
|
|||||||
* .then(console.log)
|
* .then(console.log)
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
fetch(options) {
|
async fetch(options) {
|
||||||
if (!options) return this._fetchMany();
|
if (!options) return this._fetchMany();
|
||||||
if (typeof options === 'string') {
|
if (typeof options === 'string') {
|
||||||
const code = resolveInviteCode(options);
|
const code = resolveInviteCode(options);
|
||||||
if (!code) return Promise.reject(new DiscordjsError(ErrorCodes.InviteResolveCode));
|
if (!code) throw new DiscordjsError(ErrorCodes.InviteResolveCode);
|
||||||
return this._fetchSingle({ code, cache: true });
|
return this._fetchSingle({ code, cache: true });
|
||||||
}
|
}
|
||||||
if (!options.code) {
|
if (!options.code) {
|
||||||
if (options.channelId) {
|
if (options.channelId) {
|
||||||
const id = this.guild.channels.resolveId(options.channelId);
|
const id = this.guild.channels.resolveId(options.channelId);
|
||||||
if (!id) return Promise.reject(new DiscordjsError(ErrorCodes.GuildChannelResolve));
|
if (!id) throw new DiscordjsError(ErrorCodes.GuildChannelResolve);
|
||||||
return this._fetchChannelMany(id, options.cache);
|
return this._fetchChannelMany(id, options.cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('cache' in options) return this._fetchMany(options.cache);
|
if ('cache' in options) return this._fetchMany(options.cache);
|
||||||
return Promise.reject(new DiscordjsError(ErrorCodes.InviteResolveCode));
|
throw new DiscordjsError(ErrorCodes.InviteResolveCode);
|
||||||
}
|
}
|
||||||
return this._fetchSingle({
|
return this._fetchSingle({
|
||||||
...options,
|
...options,
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ const { resolveImage } = require('../util/DataResolver');
|
|||||||
const Events = require('../util/Events');
|
const Events = require('../util/Events');
|
||||||
const PermissionsBitField = require('../util/PermissionsBitField');
|
const PermissionsBitField = require('../util/PermissionsBitField');
|
||||||
const SystemChannelFlagsBitField = require('../util/SystemChannelFlagsBitField');
|
const SystemChannelFlagsBitField = require('../util/SystemChannelFlagsBitField');
|
||||||
|
const { _transformAPIIncidentsData } = require('../util/Transformers.js');
|
||||||
const { resolveColor } = require('../util/Util');
|
const { resolveColor } = require('../util/Util');
|
||||||
|
|
||||||
let cacheWarningEmitted = false;
|
let cacheWarningEmitted = false;
|
||||||
@@ -281,6 +282,39 @@ class GuildManager extends CachedManager {
|
|||||||
return data.reduce((coll, guild) => coll.set(guild.id, new OAuth2Guild(this.client, guild)), new Collection());
|
return data.reduce((coll, guild) => coll.set(guild.id, new OAuth2Guild(this.client, guild)), new Collection());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
* Returns a URL for the PNG widget of a guild.
|
||||||
* @param {GuildResolvable} guild The guild of the widget image
|
* @param {GuildResolvable} guild The guild of the widget image
|
||||||
|
|||||||
@@ -54,8 +54,8 @@ class GuildMemberManager extends CachedManager {
|
|||||||
resolve(member) {
|
resolve(member) {
|
||||||
const memberResolvable = super.resolve(member);
|
const memberResolvable = super.resolve(member);
|
||||||
if (memberResolvable) return memberResolvable;
|
if (memberResolvable) return memberResolvable;
|
||||||
const userResolvable = this.client.users.resolveId(member);
|
const userId = this.client.users.resolveId(member);
|
||||||
if (userResolvable) return super.resolve(userResolvable);
|
if (userId) return this.cache.get(userId) ?? null;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,8 +67,8 @@ class GuildMemberManager extends CachedManager {
|
|||||||
resolveId(member) {
|
resolveId(member) {
|
||||||
const memberResolvable = super.resolveId(member);
|
const memberResolvable = super.resolveId(member);
|
||||||
if (memberResolvable) return memberResolvable;
|
if (memberResolvable) return memberResolvable;
|
||||||
const userResolvable = this.client.users.resolveId(member);
|
const userId = this.client.users.resolveId(member);
|
||||||
return this.cache.has(userResolvable) ? userResolvable : null;
|
return this.cache.has(userId) ? userId : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -144,7 +144,7 @@ class GuildMemberManager extends CachedManager {
|
|||||||
*/
|
*/
|
||||||
get me() {
|
get me() {
|
||||||
return (
|
return (
|
||||||
this.resolve(this.client.user.id) ??
|
this.cache.get(this.client.user.id) ??
|
||||||
(this.client.options.partials.includes(Partials.GuildMember)
|
(this.client.options.partials.includes(Partials.GuildMember)
|
||||||
? this._add({ user: { id: this.client.user.id } }, true)
|
? this._add({ user: { id: this.client.user.id } }, true)
|
||||||
: null)
|
: null)
|
||||||
@@ -223,7 +223,7 @@ class GuildMemberManager extends CachedManager {
|
|||||||
return this._add(data, cache);
|
return this._add(data, cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
_fetchMany({
|
async _fetchMany({
|
||||||
limit = 0,
|
limit = 0,
|
||||||
withPresences: presences,
|
withPresences: presences,
|
||||||
users,
|
users,
|
||||||
@@ -231,7 +231,7 @@ class GuildMemberManager extends CachedManager {
|
|||||||
time = 120e3,
|
time = 120e3,
|
||||||
nonce = DiscordSnowflake.generate().toString(),
|
nonce = DiscordSnowflake.generate().toString(),
|
||||||
} = {}) {
|
} = {}) {
|
||||||
if (nonce.length > 32) return Promise.reject(new DiscordjsRangeError(ErrorCodes.MemberFetchNonceLength));
|
if (nonce.length > 32) throw new DiscordjsRangeError(ErrorCodes.MemberFetchNonceLength);
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!query && !users) query = '';
|
if (!query && !users) query = '';
|
||||||
@@ -461,7 +461,7 @@ class GuildMemberManager extends CachedManager {
|
|||||||
*/
|
*/
|
||||||
async kick(user, reason) {
|
async kick(user, reason) {
|
||||||
const id = this.client.users.resolveId(user);
|
const id = this.client.users.resolveId(user);
|
||||||
if (!id) return Promise.reject(new DiscordjsTypeError(ErrorCodes.InvalidType, 'user', 'UserResolvable'));
|
if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'user', 'UserResolvable');
|
||||||
|
|
||||||
await this.client.rest.delete(Routes.guildMember(this.guild.id, id), { reason });
|
await this.client.rest.delete(Routes.guildMember(this.guild.id, id), { reason });
|
||||||
|
|
||||||
@@ -535,7 +535,7 @@ class GuildMemberManager extends CachedManager {
|
|||||||
*/
|
*/
|
||||||
async addRole(options) {
|
async addRole(options) {
|
||||||
const { user, role, reason } = options;
|
const { user, role, reason } = options;
|
||||||
const userId = this.guild.members.resolveId(user);
|
const userId = this.resolveId(user);
|
||||||
const roleId = this.guild.roles.resolveId(role);
|
const roleId = this.guild.roles.resolveId(role);
|
||||||
await this.client.rest.put(Routes.guildMemberRole(this.guild.id, userId, roleId), { reason });
|
await this.client.rest.put(Routes.guildMemberRole(this.guild.id, userId, roleId), { reason });
|
||||||
|
|
||||||
@@ -549,7 +549,7 @@ class GuildMemberManager extends CachedManager {
|
|||||||
*/
|
*/
|
||||||
async removeRole(options) {
|
async removeRole(options) {
|
||||||
const { user, role, reason } = options;
|
const { user, role, reason } = options;
|
||||||
const userId = this.guild.members.resolveId(user);
|
const userId = this.resolveId(user);
|
||||||
const roleId = this.guild.roles.resolveId(role);
|
const roleId = this.guild.roles.resolveId(role);
|
||||||
await this.client.rest.delete(Routes.guildMemberRole(this.guild.id, userId, roleId), { reason });
|
await this.client.rest.delete(Routes.guildMemberRole(this.guild.id, userId, roleId), { reason });
|
||||||
|
|
||||||
|
|||||||
@@ -101,6 +101,8 @@ class GuildMemberRoleManager extends DataManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a role (or multiple roles) to the member.
|
* 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 {RoleResolvable|RoleResolvable[]|Collection<Snowflake, Role>} roleOrRoles The role or roles to add
|
||||||
* @param {string} [reason] Reason for adding the role(s)
|
* @param {string} [reason] Reason for adding the role(s)
|
||||||
* @returns {Promise<GuildMember>}
|
* @returns {Promise<GuildMember>}
|
||||||
@@ -138,6 +140,8 @@ class GuildMemberRoleManager extends DataManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a role (or multiple roles) from the member.
|
* 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 {RoleResolvable|RoleResolvable[]|Collection<Snowflake, Role>} roleOrRoles The role or roles to remove
|
||||||
* @param {string} [reason] Reason for removing the role(s)
|
* @param {string} [reason] Reason for removing the role(s)
|
||||||
* @returns {Promise<GuildMember>}
|
* @returns {Promise<GuildMember>}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const CachedManager = require('./CachedManager');
|
|||||||
const { DiscordjsTypeError, DiscordjsError, ErrorCodes } = require('../errors');
|
const { DiscordjsTypeError, DiscordjsError, ErrorCodes } = require('../errors');
|
||||||
const { GuildScheduledEvent } = require('../structures/GuildScheduledEvent');
|
const { GuildScheduledEvent } = require('../structures/GuildScheduledEvent');
|
||||||
const { resolveImage } = require('../util/DataResolver');
|
const { resolveImage } = require('../util/DataResolver');
|
||||||
|
const { _transformGuildScheduledEventRecurrenceRule } = require('../util/Transformers');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages API methods for GuildScheduledEvents and stores their cache.
|
* Manages API methods for GuildScheduledEvents and stores their cache.
|
||||||
@@ -36,6 +37,18 @@ class GuildScheduledEventManager extends CachedManager {
|
|||||||
* @typedef {Snowflake|GuildScheduledEvent} GuildScheduledEventResolvable
|
* @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.
|
* Options used to create a guild scheduled event.
|
||||||
* @typedef {Object} GuildScheduledEventCreateOptions
|
* @typedef {Object} GuildScheduledEventCreateOptions
|
||||||
@@ -54,6 +67,8 @@ class GuildScheduledEventManager extends CachedManager {
|
|||||||
* <warn>This is required if `entityType` is {@link GuildScheduledEventEntityType.External}</warn>
|
* <warn>This is required if `entityType` is {@link GuildScheduledEventEntityType.External}</warn>
|
||||||
* @property {?(BufferResolvable|Base64Resolvable)} [image] The cover image of the guild scheduled event
|
* @property {?(BufferResolvable|Base64Resolvable)} [image] The cover image of the guild scheduled event
|
||||||
* @property {string} [reason] The reason for creating the guild scheduled event
|
* @property {string} [reason] The reason for creating the guild scheduled event
|
||||||
|
* @property {GuildScheduledEventRecurrenceRuleOptions} [recurrenceRule]
|
||||||
|
* The recurrence rule of the guild scheduled event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -81,6 +96,7 @@ class GuildScheduledEventManager extends CachedManager {
|
|||||||
entityMetadata,
|
entityMetadata,
|
||||||
reason,
|
reason,
|
||||||
image,
|
image,
|
||||||
|
recurrenceRule,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
let entity_metadata, channel_id;
|
let entity_metadata, channel_id;
|
||||||
@@ -104,6 +120,7 @@ class GuildScheduledEventManager extends CachedManager {
|
|||||||
entity_type: entityType,
|
entity_type: entityType,
|
||||||
entity_metadata,
|
entity_metadata,
|
||||||
image: image && (await resolveImage(image)),
|
image: image && (await resolveImage(image)),
|
||||||
|
recurrence_rule: recurrenceRule && _transformGuildScheduledEventRecurrenceRule(recurrenceRule),
|
||||||
},
|
},
|
||||||
reason,
|
reason,
|
||||||
});
|
});
|
||||||
@@ -153,10 +170,7 @@ class GuildScheduledEventManager extends CachedManager {
|
|||||||
|
|
||||||
return data.reduce(
|
return data.reduce(
|
||||||
(coll, rawGuildScheduledEventData) =>
|
(coll, rawGuildScheduledEventData) =>
|
||||||
coll.set(
|
coll.set(rawGuildScheduledEventData.id, this._add(rawGuildScheduledEventData, options.cache)),
|
||||||
rawGuildScheduledEventData.id,
|
|
||||||
this.guild.scheduledEvents._add(rawGuildScheduledEventData, options.cache),
|
|
||||||
),
|
|
||||||
new Collection(),
|
new Collection(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -178,6 +192,8 @@ class GuildScheduledEventManager extends CachedManager {
|
|||||||
* {@link GuildScheduledEventEntityType.External}</warn>
|
* {@link GuildScheduledEventEntityType.External}</warn>
|
||||||
* @property {?(BufferResolvable|Base64Resolvable)} [image] The cover image of the guild scheduled event
|
* @property {?(BufferResolvable|Base64Resolvable)} [image] The cover image of the guild scheduled event
|
||||||
* @property {string} [reason] The reason for editing the guild scheduled event
|
* @property {string} [reason] The reason for editing the guild scheduled event
|
||||||
|
* @property {?GuildScheduledEventRecurrenceRuleOptions} [recurrenceRule]
|
||||||
|
* The recurrence rule of the guild scheduled event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -203,6 +219,7 @@ class GuildScheduledEventManager extends CachedManager {
|
|||||||
entityMetadata,
|
entityMetadata,
|
||||||
reason,
|
reason,
|
||||||
image,
|
image,
|
||||||
|
recurrenceRule,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
let entity_metadata;
|
let entity_metadata;
|
||||||
@@ -224,6 +241,7 @@ class GuildScheduledEventManager extends CachedManager {
|
|||||||
status,
|
status,
|
||||||
image: image && (await resolveImage(image)),
|
image: image && (await resolveImage(image)),
|
||||||
entity_metadata,
|
entity_metadata,
|
||||||
|
recurrence_rule: recurrenceRule && _transformGuildScheduledEventRecurrenceRule(recurrenceRule),
|
||||||
},
|
},
|
||||||
reason,
|
reason,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -62,15 +62,13 @@ class PermissionOverwriteManager extends CachedManager {
|
|||||||
* },
|
* },
|
||||||
* ], 'Needed to change permissions');
|
* ], 'Needed to change permissions');
|
||||||
*/
|
*/
|
||||||
set(overwrites, reason) {
|
async set(overwrites, reason) {
|
||||||
if (!Array.isArray(overwrites) && !(overwrites instanceof Collection)) {
|
if (!Array.isArray(overwrites) && !(overwrites instanceof Collection)) {
|
||||||
return Promise.reject(
|
throw new DiscordjsTypeError(
|
||||||
new DiscordjsTypeError(
|
ErrorCodes.InvalidType,
|
||||||
ErrorCodes.InvalidType,
|
'overwrites',
|
||||||
'overwrites',
|
'Array or Collection of Permission Overwrites',
|
||||||
'Array or Collection of Permission Overwrites',
|
true,
|
||||||
true,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return this.channel.edit({ permissionOverwrites: overwrites, reason });
|
return this.channel.edit({ permissionOverwrites: overwrites, reason });
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ class PresenceManager extends CachedManager {
|
|||||||
resolve(presence) {
|
resolve(presence) {
|
||||||
const presenceResolvable = super.resolve(presence);
|
const presenceResolvable = super.resolve(presence);
|
||||||
if (presenceResolvable) return presenceResolvable;
|
if (presenceResolvable) return presenceResolvable;
|
||||||
const UserResolvable = this.client.users.resolveId(presence);
|
const userId = this.client.users.resolveId(presence);
|
||||||
return super.resolve(UserResolvable);
|
return super.cache.get(userId) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,8 +50,8 @@ class PresenceManager extends CachedManager {
|
|||||||
resolveId(presence) {
|
resolveId(presence) {
|
||||||
const presenceResolvable = super.resolveId(presence);
|
const presenceResolvable = super.resolveId(presence);
|
||||||
if (presenceResolvable) return presenceResolvable;
|
if (presenceResolvable) return presenceResolvable;
|
||||||
const userResolvable = this.client.users.resolveId(presence);
|
const userId = this.client.users.resolveId(presence);
|
||||||
return this.cache.has(userResolvable) ? userResolvable : null;
|
return this.cache.has(userId) ? userId : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
81
packages/discord.js/src/managers/SubscriptionManager.js
Normal file
81
packages/discord.js/src/managers/SubscriptionManager.js
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { Collection } = require('@discordjs/collection');
|
||||||
|
const { makeURLSearchParams } = require('@discordjs/rest');
|
||||||
|
const { Routes } = require('discord-api-types/v10');
|
||||||
|
const CachedManager = require('./CachedManager');
|
||||||
|
const { DiscordjsTypeError, ErrorCodes } = require('../errors/index');
|
||||||
|
const { Subscription } = require('../structures/Subscription');
|
||||||
|
const { resolveSKUId } = require('../util/Util');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages API methods for subscriptions and stores their cache.
|
||||||
|
* @extends {CachedManager}
|
||||||
|
*/
|
||||||
|
class SubscriptionManager extends CachedManager {
|
||||||
|
constructor(client, iterable) {
|
||||||
|
super(client, Subscription, iterable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cache of this manager
|
||||||
|
* @type {Collection<Snowflake, Subscription>}
|
||||||
|
* @name SubscriptionManager#cache
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options used to fetch a subscription
|
||||||
|
* @typedef {BaseFetchOptions} FetchSubscriptionOptions
|
||||||
|
* @property {SKUResolvable} sku The SKU to fetch the subscription for
|
||||||
|
* @property {Snowflake} subscriptionId The id of the subscription to fetch
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options used to fetch subscriptions
|
||||||
|
* @typedef {Object} FetchSubscriptionsOptions
|
||||||
|
* @property {Snowflake} [after] Consider only subscriptions after this subscription id
|
||||||
|
* @property {Snowflake} [before] Consider only subscriptions before this subscription id
|
||||||
|
* @property {number} [limit] The maximum number of subscriptions to fetch
|
||||||
|
* @property {SKUResolvable} sku The SKU to fetch subscriptions for
|
||||||
|
* @property {UserResolvable} user The user to fetch entitlements for
|
||||||
|
* <warn>If both `before` and `after` are provided, only `before` is respected</warn>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches subscriptions for this application
|
||||||
|
* @param {FetchSubscriptionOptions|FetchSubscriptionsOptions} [options={}] Options for fetching the subscriptions
|
||||||
|
* @returns {Promise<Subscription|Collection<Snowflake, Subscription>>}
|
||||||
|
*/
|
||||||
|
async fetch(options = {}) {
|
||||||
|
if (typeof options !== 'object') throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true);
|
||||||
|
|
||||||
|
const { after, before, cache, limit, sku, subscriptionId, user } = options;
|
||||||
|
|
||||||
|
const skuId = resolveSKUId(sku);
|
||||||
|
|
||||||
|
if (!skuId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'sku', 'SKUResolvable');
|
||||||
|
|
||||||
|
if (subscriptionId) {
|
||||||
|
const subscription = await this.client.rest.get(Routes.skuSubscription(skuId, subscriptionId));
|
||||||
|
|
||||||
|
return this._add(subscription, cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
const query = makeURLSearchParams({
|
||||||
|
limit,
|
||||||
|
user_id: this.client.users.resolveId(user) ?? undefined,
|
||||||
|
sku_id: skuId,
|
||||||
|
before,
|
||||||
|
after,
|
||||||
|
});
|
||||||
|
|
||||||
|
const subscriptions = await this.client.rest.get(Routes.skuSubscriptions(skuId), { query });
|
||||||
|
|
||||||
|
return subscriptions.reduce(
|
||||||
|
(coll, subscription) => coll.set(subscription.id, this._add(subscription, cache)),
|
||||||
|
new Collection(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.SubscriptionManager = SubscriptionManager;
|
||||||
@@ -97,7 +97,7 @@ class ThreadManager extends CachedManager {
|
|||||||
* Data that can be resolved to a Date object. This can be:
|
* Data that can be resolved to a Date object. This can be:
|
||||||
* * A Date object
|
* * A Date object
|
||||||
* * A number representing a timestamp
|
* * A number representing a timestamp
|
||||||
* * An [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) string
|
* * An {@link https://en.wikipedia.org/wiki/ISO_8601 ISO 8601} string
|
||||||
* @typedef {Date|number|string} DateResolvable
|
* @typedef {Date|number|string} DateResolvable
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const process = require('node:process');
|
||||||
const { Collection } = require('@discordjs/collection');
|
const { Collection } = require('@discordjs/collection');
|
||||||
const { makeURLSearchParams } = require('@discordjs/rest');
|
const { makeURLSearchParams } = require('@discordjs/rest');
|
||||||
const { Routes } = require('discord-api-types/v10');
|
const { Routes } = require('discord-api-types/v10');
|
||||||
const CachedManager = require('./CachedManager');
|
const CachedManager = require('./CachedManager');
|
||||||
const { DiscordjsTypeError, ErrorCodes } = require('../errors');
|
const { DiscordjsTypeError, ErrorCodes } = require('../errors');
|
||||||
const ThreadMember = require('../structures/ThreadMember');
|
const ThreadMember = require('../structures/ThreadMember');
|
||||||
|
const { emitDeprecationWarningForRemoveThreadMember } = require('../util/Util');
|
||||||
|
|
||||||
|
let deprecationEmittedForAdd = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages API methods for GuildMembers and stores their cache.
|
* Manages API methods for GuildMembers and stores their cache.
|
||||||
@@ -53,7 +57,7 @@ class ThreadMemberManager extends CachedManager {
|
|||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
get me() {
|
get me() {
|
||||||
return this.resolve(this.client.user.id);
|
return this.cache.get(this.client.user.id) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -71,8 +75,8 @@ class ThreadMemberManager extends CachedManager {
|
|||||||
resolve(member) {
|
resolve(member) {
|
||||||
const memberResolvable = super.resolve(member);
|
const memberResolvable = super.resolve(member);
|
||||||
if (memberResolvable) return memberResolvable;
|
if (memberResolvable) return memberResolvable;
|
||||||
const userResolvable = this.client.users.resolveId(member);
|
const userId = this.client.users.resolveId(member);
|
||||||
if (userResolvable) return super.resolve(userResolvable);
|
if (userId) return super.cache.get(userId) ?? null;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,9 +96,20 @@ class ThreadMemberManager extends CachedManager {
|
|||||||
* Adds a member to the thread.
|
* Adds a member to the thread.
|
||||||
* @param {UserResolvable|'@me'} member The member to add
|
* @param {UserResolvable|'@me'} member The member to add
|
||||||
* @param {string} [reason] The reason for adding this member
|
* @param {string} [reason] The reason for adding this member
|
||||||
|
* <warn>This parameter is **deprecated**. Reasons cannot be used.</warn>
|
||||||
* @returns {Promise<Snowflake>}
|
* @returns {Promise<Snowflake>}
|
||||||
*/
|
*/
|
||||||
async add(member, reason) {
|
async add(member, reason) {
|
||||||
|
if (reason !== undefined && !deprecationEmittedForAdd) {
|
||||||
|
process.emitWarning(
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
'The reason parameter of ThreadMemberManager#add() is deprecated as Discord does not parse them. It will be removed in the next major version.',
|
||||||
|
'DeprecationWarning',
|
||||||
|
);
|
||||||
|
|
||||||
|
deprecationEmittedForAdd = true;
|
||||||
|
}
|
||||||
|
|
||||||
const id = member === '@me' ? member : this.client.users.resolveId(member);
|
const id = member === '@me' ? member : this.client.users.resolveId(member);
|
||||||
if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'member', 'UserResolvable');
|
if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'member', 'UserResolvable');
|
||||||
await this.client.rest.put(Routes.threadMembers(this.thread.id, id), { reason });
|
await this.client.rest.put(Routes.threadMembers(this.thread.id, id), { reason });
|
||||||
@@ -105,9 +120,14 @@ class ThreadMemberManager extends CachedManager {
|
|||||||
* Remove a user from the thread.
|
* Remove a user from the thread.
|
||||||
* @param {UserResolvable|'@me'} member The member to remove
|
* @param {UserResolvable|'@me'} member The member to remove
|
||||||
* @param {string} [reason] The reason for removing this member from the thread
|
* @param {string} [reason] The reason for removing this member from the thread
|
||||||
|
* <warn>This parameter is **deprecated**. Reasons cannot be used.</warn>
|
||||||
* @returns {Promise<Snowflake>}
|
* @returns {Promise<Snowflake>}
|
||||||
*/
|
*/
|
||||||
async remove(member, reason) {
|
async remove(member, reason) {
|
||||||
|
if (reason !== undefined) {
|
||||||
|
emitDeprecationWarningForRemoveThreadMember(this.constructor.name);
|
||||||
|
}
|
||||||
|
|
||||||
const id = member === '@me' ? member : this.client.users.resolveId(member);
|
const id = member === '@me' ? member : this.client.users.resolveId(member);
|
||||||
if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'member', 'UserResolvable');
|
if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'member', 'UserResolvable');
|
||||||
await this.client.rest.delete(Routes.threadMembers(this.thread.id, id), { reason });
|
await this.client.rest.delete(Routes.threadMembers(this.thread.id, id), { reason });
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const { GuildMember } = require('../structures/GuildMember');
|
|||||||
const { Message } = require('../structures/Message');
|
const { Message } = require('../structures/Message');
|
||||||
const ThreadMember = require('../structures/ThreadMember');
|
const ThreadMember = require('../structures/ThreadMember');
|
||||||
const User = require('../structures/User');
|
const User = require('../structures/User');
|
||||||
|
const { emitDeprecationWarningForUserFetchFlags } = require('../util/Util');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages API methods for users and stores their cache.
|
* Manages API methods for users and stores their cache.
|
||||||
@@ -100,8 +101,11 @@ class UserManager extends CachedManager {
|
|||||||
* @param {UserResolvable} user The UserResolvable to identify
|
* @param {UserResolvable} user The UserResolvable to identify
|
||||||
* @param {BaseFetchOptions} [options] Additional options for this fetch
|
* @param {BaseFetchOptions} [options] Additional options for this fetch
|
||||||
* @returns {Promise<UserFlagsBitField>}
|
* @returns {Promise<UserFlagsBitField>}
|
||||||
|
* @deprecated <warn>This method is deprecated and will be removed in the next major version.
|
||||||
|
* Flags may still be retrieved via {@link UserManager#fetch}.</warn>
|
||||||
*/
|
*/
|
||||||
async fetchFlags(user, options) {
|
async fetchFlags(user, options) {
|
||||||
|
emitDeprecationWarningForUserFetchFlags(this.constructor.name);
|
||||||
return (await this.fetch(user, options)).flags;
|
return (await this.fetch(user, options)).flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ class Shard extends EventEmitter {
|
|||||||
* before resolving (`-1` or `Infinity` for no wait)
|
* before resolving (`-1` or `Infinity` for no wait)
|
||||||
* @returns {Promise<ChildProcess>}
|
* @returns {Promise<ChildProcess>}
|
||||||
*/
|
*/
|
||||||
spawn(timeout = 30_000) {
|
async spawn(timeout = 30_000) {
|
||||||
if (this.process) throw new DiscordjsError(ErrorCodes.ShardingProcessExists, this.id);
|
if (this.process) throw new DiscordjsError(ErrorCodes.ShardingProcessExists, this.id);
|
||||||
if (this.worker) throw new DiscordjsError(ErrorCodes.ShardingWorkerExists, this.id);
|
if (this.worker) throw new DiscordjsError(ErrorCodes.ShardingWorkerExists, this.id);
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ class Shard extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
this.emit(ShardEvents.Spawn, child);
|
this.emit(ShardEvents.Spawn, child);
|
||||||
|
|
||||||
if (timeout === -1 || timeout === Infinity) return Promise.resolve(child);
|
if (timeout === -1 || timeout === Infinity) return child;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const cleanup = () => {
|
const cleanup = () => {
|
||||||
clearTimeout(spawnTimeoutTimer);
|
clearTimeout(spawnTimeoutTimer);
|
||||||
@@ -260,10 +260,10 @@ class Shard extends EventEmitter {
|
|||||||
* .then(count => console.log(`${count} guilds in shard ${shard.id}`))
|
* .then(count => console.log(`${count} guilds in shard ${shard.id}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
fetchClientValue(prop) {
|
async fetchClientValue(prop) {
|
||||||
// Shard is dead (maybe respawning), don't cache anything and error immediately
|
// Shard is dead (maybe respawning), don't cache anything and error immediately
|
||||||
if (!this.process && !this.worker) {
|
if (!this.process && !this.worker) {
|
||||||
return Promise.reject(new DiscordjsError(ErrorCodes.ShardingNoChildExists, this.id));
|
throw new DiscordjsError(ErrorCodes.ShardingNoChildExists, this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cached promise from previous call
|
// Cached promise from previous call
|
||||||
@@ -302,13 +302,13 @@ class Shard extends EventEmitter {
|
|||||||
* @param {*} [context] The context for the eval
|
* @param {*} [context] The context for the eval
|
||||||
* @returns {Promise<*>} Result of the script execution
|
* @returns {Promise<*>} Result of the script execution
|
||||||
*/
|
*/
|
||||||
eval(script, context) {
|
async eval(script, context) {
|
||||||
// Stringify the script if it's a Function
|
// Stringify the script if it's a Function
|
||||||
const _eval = typeof script === 'function' ? `(${script})(this, ${JSON.stringify(context)})` : script;
|
const _eval = typeof script === 'function' ? `(${script})(this, ${JSON.stringify(context)})` : script;
|
||||||
|
|
||||||
// Shard is dead (maybe respawning), don't cache anything and error immediately
|
// Shard is dead (maybe respawning), don't cache anything and error immediately
|
||||||
if (!this.process && !this.worker) {
|
if (!this.process && !this.worker) {
|
||||||
return Promise.reject(new DiscordjsError(ErrorCodes.ShardingNoChildExists, this.id));
|
throw new DiscordjsError(ErrorCodes.ShardingNoChildExists, this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cached promise from previous call
|
// Cached promise from previous call
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const { makeError, makePlainError } = require('../util/Util');
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for sharded clients spawned as a child process/worker, such as from a {@link ShardingManager}.
|
* Helper class for sharded clients spawned as a child process/worker, such as from a {@link ShardingManager}.
|
||||||
* Utilises IPC to send and receive data to/from the master process and other shards.
|
* Utilizes IPC to send and receive data to/from the master process and other shards.
|
||||||
*/
|
*/
|
||||||
class ShardClientUtil {
|
class ShardClientUtil {
|
||||||
constructor(client, mode) {
|
constructor(client, mode) {
|
||||||
@@ -225,7 +225,8 @@ class ShardClientUtil {
|
|||||||
* Emitted when the client encounters an error.
|
* Emitted when the client encounters an error.
|
||||||
* <warn>Errors thrown within this event do not have a catch handler, it is
|
* <warn>Errors thrown within this event do not have a catch handler, it is
|
||||||
* recommended to not use async functions as `error` event handlers. See the
|
* recommended to not use async functions as `error` event handlers. See the
|
||||||
* [Node.js docs](https://nodejs.org/api/events.html#capture-rejections-of-promises) for details.</warn>
|
* {@link https://nodejs.org/api/events.html#capture-rejections-of-promises Node.js documentation}
|
||||||
|
* for details.)</warn>
|
||||||
* @event Client#error
|
* @event Client#error
|
||||||
* @param {Error} error The error encountered
|
* @param {Error} error The error encountered
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const { fetchRecommendedShardCount } = require('../util/Util');
|
|||||||
* This is a utility class that makes multi-process sharding of a bot an easy and painless experience.
|
* This is a utility class that makes multi-process sharding of a bot an easy and painless experience.
|
||||||
* It works by spawning a self-contained {@link ChildProcess} or {@link Worker} for each individual shard, each
|
* It works by spawning a self-contained {@link ChildProcess} or {@link Worker} for each individual shard, each
|
||||||
* containing its own instance of your bot's {@link Client}. They all have a line of communication with the master
|
* containing its own instance of your bot's {@link Client}. They all have a line of communication with the master
|
||||||
* process, and there are several useful methods that utilise it in order to simplify tasks that are normally difficult
|
* process, and there are several useful methods that utilize it in order to simplify tasks that are normally difficult
|
||||||
* with sharding. It can spawn a specific number of shards or the amount that Discord suggests for the bot, and takes a
|
* with sharding. It can spawn a specific number of shards or the amount that Discord suggests for the bot, and takes a
|
||||||
* path to your main bot script to launch for each one.
|
* path to your main bot script to launch for each one.
|
||||||
* @extends {EventEmitter}
|
* @extends {EventEmitter}
|
||||||
@@ -256,9 +256,9 @@ class ShardingManager extends EventEmitter {
|
|||||||
* @param {BroadcastEvalOptions} [options={}] The options for the broadcast
|
* @param {BroadcastEvalOptions} [options={}] The options for the broadcast
|
||||||
* @returns {Promise<*|Array<*>>} Results of the script execution
|
* @returns {Promise<*|Array<*>>} Results of the script execution
|
||||||
*/
|
*/
|
||||||
broadcastEval(script, options = {}) {
|
async broadcastEval(script, options = {}) {
|
||||||
if (typeof script !== 'function') {
|
if (typeof script !== 'function') {
|
||||||
return Promise.reject(new DiscordjsTypeError(ErrorCodes.ShardingInvalidEvalBroadcast));
|
throw new DiscordjsTypeError(ErrorCodes.ShardingInvalidEvalBroadcast);
|
||||||
}
|
}
|
||||||
return this._performOnShards('eval', [`(${script})(this, ${JSON.stringify(options.context)})`], options.shard);
|
return this._performOnShards('eval', [`(${script})(this, ${JSON.stringify(options.context)})`], options.shard);
|
||||||
}
|
}
|
||||||
@@ -285,16 +285,16 @@ class ShardingManager extends EventEmitter {
|
|||||||
* @returns {Promise<*|Array<*>>} Results of the method execution
|
* @returns {Promise<*|Array<*>>} Results of the method execution
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_performOnShards(method, args, shard) {
|
async _performOnShards(method, args, shard) {
|
||||||
if (this.shards.size === 0) return Promise.reject(new DiscordjsError(ErrorCodes.ShardingNoShards));
|
if (this.shards.size === 0) throw new DiscordjsError(ErrorCodes.ShardingNoShards);
|
||||||
|
|
||||||
if (typeof shard === 'number') {
|
if (typeof shard === 'number') {
|
||||||
if (this.shards.has(shard)) return this.shards.get(shard)[method](...args);
|
if (this.shards.has(shard)) return this.shards.get(shard)[method](...args);
|
||||||
return Promise.reject(new DiscordjsError(ErrorCodes.ShardingShardNotFound, shard));
|
throw new DiscordjsError(ErrorCodes.ShardingShardNotFound, shard);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.shards.size !== this.shardList.length) {
|
if (this.shards.size !== this.shardList.length) {
|
||||||
return Promise.reject(new DiscordjsError(ErrorCodes.ShardingInProcess));
|
throw new DiscordjsError(ErrorCodes.ShardingInProcess);
|
||||||
}
|
}
|
||||||
|
|
||||||
const promises = [];
|
const promises = [];
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user