mirror of
https://github.com/discordjs/discord.js.git
synced 2026-05-24 12:30:08 +00:00
Compare commits
35 Commits
@discordjs
...
@discordjs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ca3974301 | ||
|
|
3202c91c5a | ||
|
|
f3f34f07b3 | ||
|
|
f8ed71bfca | ||
|
|
e1176faa27 | ||
|
|
aa59a409b3 | ||
|
|
7fa698d23e | ||
|
|
b9df37a89f | ||
|
|
ad75be9a9c | ||
|
|
70c733bb9a | ||
|
|
a3287782b5 | ||
|
|
0ccc243c8f | ||
|
|
0a7953e463 | ||
|
|
6aa623240e | ||
|
|
6266b0c1e3 | ||
|
|
9720e55534 | ||
|
|
ad36c0be77 | ||
|
|
5987dbe5cf | ||
|
|
5244fe3c1c | ||
|
|
349766dd69 | ||
|
|
7a1095b66b | ||
|
|
10009a43ee | ||
|
|
8d8e6c03de | ||
|
|
dfadcbc2fd | ||
|
|
546d48655f | ||
|
|
f8739bd9c0 | ||
|
|
f2ae1f9348 | ||
|
|
3401fd4eb6 | ||
|
|
fdbd229832 | ||
|
|
9e8e2411c1 | ||
|
|
c02ced9a22 | ||
|
|
8c5a7f80ef | ||
|
|
14018b0118 | ||
|
|
8095723604 | ||
|
|
e17bb54c85 |
15
.github/workflows/documentation.yml
vendored
15
.github/workflows/documentation.yml
vendored
@@ -7,6 +7,11 @@ on:
|
||||
- '!docs'
|
||||
tags:
|
||||
- '**'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ref:
|
||||
description: 'The branch, tag or SHA to checkout'
|
||||
required: true
|
||||
jobs:
|
||||
build:
|
||||
name: Build documentation
|
||||
@@ -19,6 +24,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.inputs.ref || '' }}
|
||||
|
||||
- name: Install node.js v16
|
||||
uses: actions/setup-node@v2
|
||||
@@ -65,7 +72,7 @@ jobs:
|
||||
package: ['builders', 'collection', 'discord.js', 'proxy', 'rest', 'voice']
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
BRANCH_NAME: ${{ needs.build.outputs.BRANCH_NAME }}
|
||||
BRANCH_NAME: ${{ github.event.inputs.ref || needs.build.outputs.BRANCH_NAME }}
|
||||
BRANCH_OR_TAG: ${{ needs.build.outputs.BRANCH_OR_TAG }}
|
||||
SHA: ${{ needs.build.outputs.SHA }}
|
||||
steps:
|
||||
@@ -108,14 +115,14 @@ jobs:
|
||||
path: 'out'
|
||||
|
||||
- name: Extract package and semver from tag
|
||||
if: env.BRANCH_OR_TAG == 'tag'
|
||||
if: ${{ github.event.inputs.ref || env.BRANCH_OR_TAG == 'tag' }}
|
||||
id: extract-tag
|
||||
uses: ./packages/actions/src/formatTag
|
||||
with:
|
||||
tag: ${{ env.BRANCH_NAME }}
|
||||
|
||||
- name: Move docs to correct directory
|
||||
if: env.BRANCH_OR_TAG == 'tag'
|
||||
if: ${{ (github.event.inputs.ref || env.BRANCH_OR_TAG == 'tag') && matrix.package == steps.extract-tag.outputs.package }}
|
||||
env:
|
||||
PACKAGE: ${{ steps.extract-tag.outputs.package }}
|
||||
SEMVER: ${{ steps.extract-tag.outputs.semver }}
|
||||
@@ -124,7 +131,7 @@ jobs:
|
||||
mv docs/${PACKAGE}/docs/docs.json out/${PACKAGE}/${SEMVER}.json
|
||||
|
||||
- name: Move docs to correct directory
|
||||
if: env.BRANCH_OR_TAG == 'branch'
|
||||
if: ${{ !github.event.inputs.ref && env.BRANCH_OR_TAG == 'branch' }}
|
||||
env:
|
||||
PACKAGE: ${{ matrix.package }}
|
||||
run: |
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
run: yarn lint --cache-dir=".turbo"
|
||||
|
||||
- name: Tests
|
||||
run: yarn test --cache-dir=".turbo"
|
||||
run: yarn test
|
||||
|
||||
- name: Build
|
||||
run: yarn build --cache-dir=".turbo"
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -26,6 +26,7 @@ dist/
|
||||
.DS_Store
|
||||
.turbo
|
||||
tsconfig.tsbuildinfo
|
||||
coverage/
|
||||
|
||||
# yarn
|
||||
.pnp.*
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "turbo run build",
|
||||
"test": "turbo run test",
|
||||
"test": "turbo run test && vitest run",
|
||||
"lint": "turbo run lint",
|
||||
"format": "turbo run format",
|
||||
"fmt": "turbo run format",
|
||||
@@ -41,10 +41,13 @@
|
||||
"@commitlint/cli": "^17.0.2",
|
||||
"@commitlint/config-angular": "^17.0.0",
|
||||
"@favware/npm-deprecate": "^1.0.4",
|
||||
"c8": "^7.11.3",
|
||||
"conventional-changelog-cli": "^2.2.2",
|
||||
"husky": "^8.0.1",
|
||||
"is-ci": "^3.0.1",
|
||||
"prettier": "^2.6.2",
|
||||
"turbo": "^1.2.16"
|
||||
"turbo": "^1.2.16",
|
||||
"vitest": "^0.13.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.9.0"
|
||||
|
||||
@@ -6,45 +6,23 @@
|
||||
<br />
|
||||
<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://www.npmjs.com/package/@discordjs/builders"><img src="https://img.shields.io/npm/v/@discordjs/builders.svg?maxAge=3600" alt="npm version" /></a>
|
||||
<a href="https://www.npmjs.com/package/@discordjs/builders"><img src="https://img.shields.io/npm/dt/@discordjs/builders.svg?maxAge=3600" alt="npm downloads" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Build status" /></a>
|
||||
<a href="https://codecov.io/gh/discordjs/builders"><img src="https://codecov.io/gh/discordjs/builders/branch/main/graph/badge.svg" alt="Code coverage" /></a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
## Installation
|
||||
|
||||
**Node.js 16.9.0 or newer is required.**
|
||||
|
||||
```sh-session
|
||||
npm install @discordjs/builders
|
||||
yarn add @discordjs/builders
|
||||
pnpm add @discordjs/builders
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Here are some examples for the builders and utilities you can find in this package:
|
||||
|
||||
- [Slash Command Builders](https://github.com/discordjs/discord.js/blob/main/packages/builders/docs/examples/Slash%20Command%20Builders.md)
|
||||
|
||||
## Links
|
||||
|
||||
- [Website](https://discord.js.org/) ([source](https://github.com/discordjs/website))
|
||||
- [Documentation](https://discord.js.org/#/docs/builders)
|
||||
- [Documentation](https://discord.js.org/#/docs)
|
||||
- [Guide](https://discordjs.guide/) ([source](https://github.com/discordjs/guide))
|
||||
See also the [Update Guide](https://discordjs.guide/additional-info/changes-in-v13.html), including updated and removed items in the library.
|
||||
- [discord.js Discord server](https://discord.gg/djs)
|
||||
- [Discord API Discord server](https://discord.gg/discord-api)
|
||||
- [GitHub](https://github.com/discordjs/discord.js/tree/main/packages/builders)
|
||||
- [npm](https://www.npmjs.com/package/@discordjs/builders)
|
||||
- [GitHub](https://github.com/discordjs/discord.js/tree/main/packages/scripts)
|
||||
- [Related libraries](https://discord.com/developers/docs/topics/community-resources#libraries)
|
||||
|
||||
## Contributing
|
||||
|
||||
Before creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the
|
||||
[documentation](https://discord.js.org/#/docs/builders).
|
||||
See [the contribution guide](https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md) if you'd like to submit a PR.
|
||||
|
||||
## Help
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { formatTag } from '../src';
|
||||
|
||||
describe('Format Tag', () => {
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
/**
|
||||
* @type {import('@babel/core').TransformOptions}
|
||||
*/
|
||||
module.exports = {
|
||||
parserOpts: { strictMode: true },
|
||||
sourceMaps: 'inline',
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
targets: { node: 'current' },
|
||||
modules: 'commonjs',
|
||||
},
|
||||
],
|
||||
'@babel/preset-typescript',
|
||||
],
|
||||
plugins: ['babel-plugin-transform-typescript-metadata', ['@babel/plugin-proposal-decorators', { legacy: true }]],
|
||||
};
|
||||
@@ -1,10 +0,0 @@
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
target: 70%
|
||||
threshold: 5%
|
||||
patch:
|
||||
default:
|
||||
target: 70%
|
||||
threshold: 5%
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* @type {import('@jest/types').Config.InitialOptions}
|
||||
*/
|
||||
module.exports = {
|
||||
testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'],
|
||||
testEnvironment: 'node',
|
||||
collectCoverage: true,
|
||||
collectCoverageFrom: ['src/**/*.ts'],
|
||||
coverageDirectory: 'coverage',
|
||||
coverageReporters: ['text', 'lcov', 'clover'],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
branches: 70,
|
||||
lines: 70,
|
||||
statements: 70,
|
||||
},
|
||||
},
|
||||
coveragePathIgnorePatterns: ['src/index.ts', 'src/formatTag/index.ts'],
|
||||
};
|
||||
@@ -5,7 +5,6 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "tsup",
|
||||
"test": "jest --pass-with-no-tests",
|
||||
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix"
|
||||
},
|
||||
@@ -48,23 +47,15 @@
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.18.2",
|
||||
"@babel/plugin-proposal-decorators": "^7.18.2",
|
||||
"@babel/preset-env": "^7.18.2",
|
||||
"@babel/preset-typescript": "^7.17.12",
|
||||
"@types/jest": "^28.1.0",
|
||||
"@types/node": "^16.11.38",
|
||||
"@typescript-eslint/eslint-plugin": "^5.27.0",
|
||||
"@typescript-eslint/parser": "^5.27.0",
|
||||
"babel-plugin-transform-typescript-metadata": "^0.3.2",
|
||||
"eslint": "^8.17.0",
|
||||
"eslint-config-marine": "^9.4.1",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"jest": "^28.1.0",
|
||||
"prettier": "^2.6.2",
|
||||
"tsup": "^6.0.1",
|
||||
"typedoc": "^0.22.17",
|
||||
"typescript": "^4.7.3"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -11,4 +11,4 @@ outputs:
|
||||
description: 'The semver string that was extracted from this tag'
|
||||
runs:
|
||||
using: node16
|
||||
main: ../../dist/formatTag/index.mjs
|
||||
main: ../../dist/formatTag/index.js
|
||||
|
||||
@@ -4,7 +4,7 @@ import { formatTag } from './formatTag';
|
||||
const tag = getInput('tag', { required: true });
|
||||
const parsed = formatTag(tag);
|
||||
|
||||
if (parsed?.groups) {
|
||||
if (parsed) {
|
||||
setOutput('package', parsed.package);
|
||||
setOutput('semver', parsed.semver);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ export default defineConfig({
|
||||
clean: true,
|
||||
dts: true,
|
||||
entryPoints: ['src/index.ts', 'src/formatTag/index.ts'],
|
||||
format: ['esm'],
|
||||
format: ['cjs'],
|
||||
minify: true,
|
||||
skipNodeModulesBundle: false,
|
||||
noExternal: ['@actions/core'],
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"releaseCommitMessageFormat": "chore(Release): publish"
|
||||
}
|
||||
@@ -2,6 +2,14 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
# [@discordjs/builders@0.15.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@0.14.0...@discordjs/builders@0.15.0) - (2022-06-05)
|
||||
|
||||
## Features
|
||||
|
||||
- Allow builders to accept rest params and arrays (#7874) ([ad75be9](https://github.com/discordjs/discord.js/commit/ad75be9a9cf90c8624495df99b75177e6c24022f))
|
||||
- Use vitest instead of jest for more speed ([8d8e6c0](https://github.com/discordjs/discord.js/commit/8d8e6c03decd7352a2aa180f6e5bc1a13602539b))
|
||||
- Add scripts package for locally used scripts ([f2ae1f9](https://github.com/discordjs/discord.js/commit/f2ae1f9348bfd893332a9060f71a8a5f272a1b8b))
|
||||
|
||||
# [@discordjs/builders@0.14.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@0.13.0...@discordjs/builders@0.14.0) - (2022-06-04)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
<a href="https://www.npmjs.com/package/@discordjs/builders"><img src="https://img.shields.io/npm/v/@discordjs/builders.svg?maxAge=3600" alt="npm version" /></a>
|
||||
<a href="https://www.npmjs.com/package/@discordjs/builders"><img src="https://img.shields.io/npm/dt/@discordjs/builders.svg?maxAge=3600" alt="npm downloads" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Build status" /></a>
|
||||
<a href="https://codecov.io/gh/discordjs/builders"><img src="https://codecov.io/gh/discordjs/builders/branch/main/graph/badge.svg" alt="Code coverage" /></a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { APIActionRowComponent, APIMessageActionRowComponent, ButtonStyle, ComponentType } from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
@@ -44,6 +45,8 @@ const rowWithSelectMenuData: APIActionRowComponent<APIMessageActionRowComponent>
|
||||
describe('Action Row Components', () => {
|
||||
describe('Assertion Tests', () => {
|
||||
test('GIVEN valid components THEN do not throw', () => {
|
||||
expect(() => new ActionRowBuilder().addComponents(new ButtonBuilder())).not.toThrowError();
|
||||
expect(() => new ActionRowBuilder().setComponents(new ButtonBuilder())).not.toThrowError();
|
||||
expect(() => new ActionRowBuilder().addComponents([new ButtonBuilder()])).not.toThrowError();
|
||||
expect(() => new ActionRowBuilder().setComponents([new ButtonBuilder()])).not.toThrowError();
|
||||
});
|
||||
@@ -82,6 +85,7 @@ describe('Action Row Components', () => {
|
||||
expect(new ActionRowBuilder().toJSON()).toEqual({ type: ComponentType.ActionRow, components: [] });
|
||||
expect(() => createComponentBuilder({ type: ComponentType.ActionRow, components: [] })).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid builder options THEN valid JSON output is given', () => {
|
||||
const rowWithButtonData: APIActionRowComponent<APIMessageActionRowComponent> = {
|
||||
type: ComponentType.ActionRow,
|
||||
@@ -122,17 +126,24 @@ describe('Action Row Components', () => {
|
||||
expect(new ActionRowBuilder().toJSON()).toEqual({ type: ComponentType.ActionRow, components: [] });
|
||||
expect(() => createComponentBuilder({ type: ComponentType.ActionRow, components: [] })).not.toThrowError();
|
||||
});
|
||||
test('GIVEN valid builder options THEN valid JSON output is given', () => {
|
||||
|
||||
test('GIVEN valid builder options THEN valid JSON output is given 2', () => {
|
||||
const button = new ButtonBuilder().setLabel('test').setStyle(ButtonStyle.Primary).setCustomId('123');
|
||||
const selectMenu = new SelectMenuBuilder()
|
||||
.setCustomId('1234')
|
||||
.setMaxValues(10)
|
||||
.setMinValues(12)
|
||||
.setOptions(
|
||||
new SelectMenuOptionBuilder().setLabel('one').setValue('one'),
|
||||
new SelectMenuOptionBuilder().setLabel('two').setValue('two'),
|
||||
)
|
||||
.setOptions([
|
||||
new SelectMenuOptionBuilder().setLabel('one').setValue('one'),
|
||||
new SelectMenuOptionBuilder().setLabel('two').setValue('two'),
|
||||
]);
|
||||
|
||||
expect(new ActionRowBuilder().addComponents(button).toJSON()).toEqual(rowWithButtonData);
|
||||
expect(new ActionRowBuilder().addComponents(selectMenu).toJSON()).toEqual(rowWithSelectMenuData);
|
||||
expect(new ActionRowBuilder().addComponents([button]).toJSON()).toEqual(rowWithButtonData);
|
||||
expect(new ActionRowBuilder().addComponents([selectMenu]).toJSON()).toEqual(rowWithSelectMenuData);
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
ButtonStyle,
|
||||
ComponentType,
|
||||
} from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { buttonLabelValidator, buttonStyleValidator } from '../../src/components/Assertions';
|
||||
import { ButtonBuilder } from '../../src/components/button/Button';
|
||||
|
||||
@@ -124,7 +125,7 @@ describe('Button Components', () => {
|
||||
expect(
|
||||
buttonComponent()
|
||||
.setCustomId(interactionData.custom_id)
|
||||
.setLabel(interactionData.label)
|
||||
.setLabel(interactionData.label!)
|
||||
.setStyle(interactionData.style)
|
||||
.setDisabled(interactionData.disabled)
|
||||
.toJSON(),
|
||||
@@ -140,7 +141,7 @@ describe('Button Components', () => {
|
||||
|
||||
expect(new ButtonBuilder(linkData).toJSON()).toEqual(linkData);
|
||||
|
||||
expect(buttonComponent().setLabel(linkData.label).setDisabled(true).setURL(linkData.url));
|
||||
expect(buttonComponent().setLabel(linkData.label!).setDisabled(true).setURL(linkData.url));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { APISelectMenuComponent, APISelectMenuOption, ComponentType } from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { SelectMenuBuilder, SelectMenuOptionBuilder } from '../../src/index';
|
||||
|
||||
const selectMenu = () => new SelectMenuBuilder();
|
||||
@@ -43,12 +44,15 @@ describe('Select Menu Components', () => {
|
||||
.setDefault(true)
|
||||
.setEmoji({ name: 'test' })
|
||||
.setDescription('description');
|
||||
expect(() => selectMenu().addOptions(option)).not.toThrowError();
|
||||
expect(() => selectMenu().setOptions(option)).not.toThrowError();
|
||||
expect(() => selectMenu().setOptions({ label: 'test', value: 'test' })).not.toThrowError();
|
||||
expect(() => selectMenu().addOptions([option])).not.toThrowError();
|
||||
expect(() => selectMenu().setOptions([option])).not.toThrowError();
|
||||
expect(() => selectMenu().setOptions([{ label: 'test', value: 'test' }])).not.toThrowError();
|
||||
expect(() =>
|
||||
selectMenu().addOptions([
|
||||
{
|
||||
selectMenu()
|
||||
.addOptions({
|
||||
label: 'test',
|
||||
value: 'test',
|
||||
emoji: {
|
||||
@@ -56,14 +60,31 @@ describe('Select Menu Components', () => {
|
||||
name: 'test',
|
||||
animated: true,
|
||||
},
|
||||
},
|
||||
]),
|
||||
})
|
||||
.addOptions([
|
||||
{
|
||||
label: 'test',
|
||||
value: 'test',
|
||||
emoji: {
|
||||
id: '123',
|
||||
name: 'test',
|
||||
animated: true,
|
||||
},
|
||||
},
|
||||
]),
|
||||
).not.toThrowError();
|
||||
|
||||
const options = new Array<APISelectMenuOption>(25).fill({ label: 'test', value: 'test' });
|
||||
expect(() => selectMenu().addOptions(...options)).not.toThrowError();
|
||||
expect(() => selectMenu().setOptions(...options)).not.toThrowError();
|
||||
expect(() => selectMenu().addOptions(options)).not.toThrowError();
|
||||
expect(() => selectMenu().setOptions(options)).not.toThrowError();
|
||||
|
||||
expect(() =>
|
||||
selectMenu()
|
||||
.addOptions({ label: 'test', value: 'test' })
|
||||
.addOptions(...new Array<APISelectMenuOption>(24).fill({ label: 'test', value: 'test' })),
|
||||
).not.toThrowError();
|
||||
expect(() =>
|
||||
selectMenu()
|
||||
.addOptions([{ label: 'test', value: 'test' }])
|
||||
@@ -79,6 +100,17 @@ describe('Select Menu Components', () => {
|
||||
expect(() => selectMenu().setDisabled(0)).toThrowError();
|
||||
expect(() => selectMenu().setPlaceholder(longStr)).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => selectMenu().addOptions({ label: 'test' })).toThrowError();
|
||||
expect(() => selectMenu().addOptions({ label: longStr, value: 'test' })).toThrowError();
|
||||
expect(() => selectMenu().addOptions({ value: longStr, label: 'test' })).toThrowError();
|
||||
expect(() => selectMenu().addOptions({ label: 'test', value: 'test', description: longStr })).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => selectMenu().addOptions({ label: 'test', value: 'test', default: 100 })).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => selectMenu().addOptions({ value: 'test' })).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => selectMenu().addOptions({ default: true })).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => selectMenu().addOptions([{ label: 'test' }])).toThrowError();
|
||||
expect(() => selectMenu().addOptions([{ label: longStr, value: 'test' }])).toThrowError();
|
||||
expect(() => selectMenu().addOptions([{ value: longStr, label: 'test' }])).toThrowError();
|
||||
@@ -91,8 +123,14 @@ describe('Select Menu Components', () => {
|
||||
expect(() => selectMenu().addOptions([{ default: true }])).toThrowError();
|
||||
|
||||
const tooManyOptions = new Array<APISelectMenuOption>(26).fill({ label: 'test', value: 'test' });
|
||||
expect(() => selectMenu().setOptions(...tooManyOptions)).toThrowError();
|
||||
expect(() => selectMenu().setOptions(tooManyOptions)).toThrowError();
|
||||
|
||||
expect(() =>
|
||||
selectMenu()
|
||||
.addOptions({ label: 'test', value: 'test' })
|
||||
.addOptions(...tooManyOptions),
|
||||
).toThrowError();
|
||||
expect(() =>
|
||||
selectMenu()
|
||||
.addOptions([{ label: 'test', value: 'test' }])
|
||||
@@ -112,6 +150,11 @@ describe('Select Menu Components', () => {
|
||||
});
|
||||
|
||||
test('GIVEN valid JSON input THEN valid JSON history is correct', () => {
|
||||
expect(
|
||||
new SelectMenuBuilder(selectMenuDataWithoutOptions)
|
||||
.addOptions(new SelectMenuOptionBuilder(selectMenuOptionData))
|
||||
.toJSON(),
|
||||
).toEqual(selectMenuData);
|
||||
expect(
|
||||
new SelectMenuBuilder(selectMenuDataWithoutOptions)
|
||||
.addOptions([new SelectMenuOptionBuilder(selectMenuOptionData)])
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { APITextInputComponent, ComponentType, TextInputStyle } from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
labelValidator,
|
||||
maxLengthValidator,
|
||||
@@ -45,7 +46,7 @@ describe('Text Input Components', () => {
|
||||
expect(() => maxLengthValidator.parse(10)).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid min length THEN validator does throw', () => {
|
||||
test('GIVEN invalid min length THEN validator does throw 2', () => {
|
||||
expect(() => maxLengthValidator.parse(4001)).toThrowError();
|
||||
});
|
||||
|
||||
@@ -61,7 +62,7 @@ describe('Text Input Components', () => {
|
||||
expect(() => placeholderValidator.parse('foobar')).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid value THEN validator does throw', () => {
|
||||
test('GIVEN invalid value THEN validator does throw 2', () => {
|
||||
expect(() => placeholderValidator.parse(superLongStr)).toThrowError();
|
||||
});
|
||||
|
||||
@@ -114,10 +115,10 @@ describe('Text Input Components', () => {
|
||||
textInputComponent()
|
||||
.setCustomId(textInputData.custom_id)
|
||||
.setLabel(textInputData.label)
|
||||
.setPlaceholder(textInputData.placeholder)
|
||||
.setMaxLength(textInputData.max_length)
|
||||
.setMinLength(textInputData.min_length)
|
||||
.setValue(textInputData.value)
|
||||
.setPlaceholder(textInputData.placeholder!)
|
||||
.setMaxLength(textInputData.max_length!)
|
||||
.setMinLength(textInputData.min_length!)
|
||||
.setValue(textInputData.value!)
|
||||
.setRequired(textInputData.required)
|
||||
.setStyle(textInputData.style)
|
||||
.toJSON(),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { PermissionFlagsBits } from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { ContextMenuCommandAssertions, ContextMenuCommandBuilder } from '../../src/index';
|
||||
|
||||
const getBuilder = () => new ContextMenuCommandBuilder();
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
ApplicationCommandOptionType,
|
||||
ChannelType,
|
||||
} from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
SlashCommandBooleanOption,
|
||||
SlashCommandChannelOption,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { APIApplicationCommandOptionChoice, ChannelType, PermissionFlagsBits } from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
SlashCommandAssertions,
|
||||
SlashCommandBooleanOption,
|
||||
@@ -313,8 +314,10 @@ describe('Slash Commands', () => {
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addBooleanOption(true)).toThrowError();
|
||||
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addBooleanOption(null)).toThrowError();
|
||||
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addBooleanOption(undefined)).toThrowError();
|
||||
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { APIModalInteractionResponseCallbackData, ComponentType, TextInputStyle } from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
@@ -48,7 +49,11 @@ describe('Modals', () => {
|
||||
|
||||
test('GIVEN valid fields THEN builder does not throw', () => {
|
||||
expect(() =>
|
||||
modal().setTitle('test').setCustomId('foobar').setComponents([new ActionRowBuilder()]),
|
||||
modal()
|
||||
.setTitle('test')
|
||||
.setCustomId('foobar')
|
||||
.setComponents(new ActionRowBuilder())
|
||||
.addComponents([new ActionRowBuilder()]),
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
@@ -74,6 +79,17 @@ describe('Modals', () => {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: ComponentType.ActionRow,
|
||||
components: [
|
||||
{
|
||||
type: ComponentType.TextInput,
|
||||
label: 'label',
|
||||
style: TextInputStyle.Paragraph,
|
||||
custom_id: 'custom id',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -83,10 +99,15 @@ describe('Modals', () => {
|
||||
modal()
|
||||
.setTitle(modalData.title)
|
||||
.setCustomId('custom id')
|
||||
.setComponents([
|
||||
new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents([
|
||||
.setComponents(
|
||||
new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(
|
||||
new TextInputBuilder().setCustomId('custom id').setLabel('label').setStyle(TextInputStyle.Paragraph),
|
||||
]),
|
||||
),
|
||||
)
|
||||
.addComponents([
|
||||
new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(
|
||||
new TextInputBuilder().setCustomId('custom id').setLabel('label').setStyle(TextInputStyle.Paragraph),
|
||||
),
|
||||
])
|
||||
.toJSON(),
|
||||
).toEqual(modalData);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { EmbedBuilder, embedLength } from '../../src';
|
||||
|
||||
const alpha = 'abcdefghijklmnopqrstuvwxyz';
|
||||
@@ -322,28 +323,29 @@ describe('Embed', () => {
|
||||
|
||||
test('GIVEN an embed using Embed#addFields THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
embed.addFields({ name: 'foo', value: 'bar' });
|
||||
embed.addFields([{ name: 'foo', value: 'bar' }]);
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({
|
||||
fields: [{ name: 'foo', value: 'bar' }],
|
||||
fields: [
|
||||
{ name: 'foo', value: 'bar' },
|
||||
{ name: 'foo', value: 'bar' },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN an embed using Embed#spliceFields THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
embed.addFields([
|
||||
{ name: 'foo', value: 'bar' },
|
||||
{ name: 'foo', value: 'baz' },
|
||||
]);
|
||||
embed.addFields({ name: 'foo', value: 'bar' }, { name: 'foo', value: 'baz' });
|
||||
|
||||
expect(embed.spliceFields(0, 1).toJSON()).toStrictEqual({
|
||||
fields: [{ name: 'foo', value: 'baz' }],
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN an embed using Embed#spliceFields THEN returns valid toJSON data', () => {
|
||||
test('GIVEN an embed using Embed#spliceFields THEN returns valid toJSON data 2', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
embed.addFields(Array.from({ length: 23 }, () => ({ name: 'foo', value: 'bar' })));
|
||||
embed.addFields(...Array.from({ length: 23 }, () => ({ name: 'foo', value: 'bar' })));
|
||||
|
||||
expect(() =>
|
||||
embed.spliceFields(0, 3, ...Array.from({ length: 5 }, () => ({ name: 'foo', value: 'bar' }))),
|
||||
@@ -352,7 +354,7 @@ describe('Embed', () => {
|
||||
|
||||
test('GIVEN an embed using Embed#spliceFields that adds additional fields resulting in fields > 25 THEN throws error', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
embed.addFields(Array.from({ length: 23 }, () => ({ name: 'foo', value: 'bar' })));
|
||||
embed.addFields(...Array.from({ length: 23 }, () => ({ name: 'foo', value: 'bar' })));
|
||||
|
||||
expect(() =>
|
||||
embed.spliceFields(0, 3, ...Array.from({ length: 8 }, () => ({ name: 'foo', value: 'bar' }))),
|
||||
@@ -362,6 +364,9 @@ describe('Embed', () => {
|
||||
test('GIVEN an embed using Embed#setFields THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() =>
|
||||
embed.setFields(...Array.from({ length: 25 }, () => ({ name: 'foo', value: 'bar' }))),
|
||||
).not.toThrowError();
|
||||
expect(() =>
|
||||
embed.setFields(Array.from({ length: 25 }, () => ({ name: 'foo', value: 'bar' }))),
|
||||
).not.toThrowError();
|
||||
@@ -370,38 +375,43 @@ describe('Embed', () => {
|
||||
test('GIVEN an embed using Embed#setFields that sets more than 25 fields THEN throws error', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() =>
|
||||
embed.setFields(...Array.from({ length: 26 }, () => ({ name: 'foo', value: 'bar' }))),
|
||||
).toThrowError();
|
||||
expect(() => embed.setFields(Array.from({ length: 26 }, () => ({ name: 'foo', value: 'bar' })))).toThrowError();
|
||||
});
|
||||
|
||||
describe('GIVEN invalid field amount THEN throws error', () => {
|
||||
test('', () => {
|
||||
test('1', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() => embed.addFields(Array.from({ length: 26 }, () => ({ name: 'foo', value: 'bar' })))).toThrowError();
|
||||
expect(() =>
|
||||
embed.addFields(...Array.from({ length: 26 }, () => ({ name: 'foo', value: 'bar' }))),
|
||||
).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('GIVEN invalid field name THEN throws error', () => {
|
||||
test('', () => {
|
||||
test('2', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() => embed.addFields([{ name: '', value: 'bar' }])).toThrowError();
|
||||
expect(() => embed.addFields({ name: '', value: 'bar' })).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('GIVEN invalid field name length THEN throws error', () => {
|
||||
test('', () => {
|
||||
test('3', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() => embed.addFields([{ name: 'a'.repeat(257), value: 'bar' }])).toThrowError();
|
||||
expect(() => embed.addFields({ name: 'a'.repeat(257), value: 'bar' })).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('GIVEN invalid field value length THEN throws error', () => {
|
||||
test('', () => {
|
||||
test('4', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() => embed.addFields([{ name: '', value: 'a'.repeat(1025) }])).toThrowError();
|
||||
expect(() => embed.addFields({ name: '', value: 'a'.repeat(1025) })).toThrowError();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { describe, test, expect, vitest } from 'vitest';
|
||||
import {
|
||||
blockQuote,
|
||||
bold,
|
||||
@@ -150,12 +151,12 @@ describe('Message formatters', () => {
|
||||
|
||||
describe('time', () => {
|
||||
test('GIVEN no arguments THEN returns "<t:${bigint}>"', () => {
|
||||
jest.useFakeTimers('modern');
|
||||
jest.setSystemTime(1566424897579);
|
||||
vitest.useFakeTimers();
|
||||
vitest.setSystemTime(1566424897579);
|
||||
|
||||
expect<`<t:${bigint}>`>(time()).toEqual('<t:1566424897>');
|
||||
|
||||
jest.useRealTimers();
|
||||
vitest.useRealTimers();
|
||||
});
|
||||
|
||||
test('GIVEN a date THEN returns "<t:${bigint}>"', () => {
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
/**
|
||||
* @type {import('@babel/core').TransformOptions}
|
||||
*/
|
||||
module.exports = {
|
||||
parserOpts: { strictMode: true },
|
||||
sourceMaps: 'inline',
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
targets: { node: 'current' },
|
||||
modules: 'commonjs',
|
||||
},
|
||||
],
|
||||
'@babel/preset-typescript',
|
||||
],
|
||||
plugins: ['babel-plugin-transform-typescript-metadata', ['@babel/plugin-proposal-decorators', { legacy: true }]],
|
||||
};
|
||||
@@ -1,10 +0,0 @@
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
target: 70%
|
||||
threshold: 5%
|
||||
patch:
|
||||
default:
|
||||
target: 70%
|
||||
threshold: 5%
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* @type {import('@jest/types').Config.InitialOptions}
|
||||
*/
|
||||
module.exports = {
|
||||
testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'],
|
||||
testEnvironment: 'node',
|
||||
collectCoverage: true,
|
||||
collectCoverageFrom: ['src/**/*.ts'],
|
||||
coverageDirectory: 'coverage',
|
||||
coverageReporters: ['text', 'lcov', 'clover'],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
branches: 70,
|
||||
lines: 70,
|
||||
statements: 70,
|
||||
},
|
||||
},
|
||||
coveragePathIgnorePatterns: ['src/index.ts'],
|
||||
};
|
||||
@@ -1,15 +1,14 @@
|
||||
{
|
||||
"name": "@discordjs/builders",
|
||||
"version": "0.14.0",
|
||||
"version": "0.15.0",
|
||||
"description": "A set of builders that you can use when creating your bot",
|
||||
"scripts": {
|
||||
"build": "tsup",
|
||||
"test": "jest --pass-with-no-tests",
|
||||
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"docs": "typedoc --json docs/typedoc-out.json src/index.ts && node scripts/docs.mjs",
|
||||
"docs": "typedoc --json docs/typedoc-out.json src/index.ts && ts-docgen -i docs/typedoc-out.json -c docs/index.yml -o docs/docs.json",
|
||||
"prepublishOnly": "yarn build && yarn lint && yarn test",
|
||||
"changelog": "git cliff --prepend ./CHANGELOG.md -l -c ./cliff.toml -r ../../ --include-path 'packages/builders/*'"
|
||||
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/builders/*'"
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.mjs",
|
||||
@@ -60,21 +59,14 @@
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.18.2",
|
||||
"@babel/plugin-proposal-decorators": "^7.18.2",
|
||||
"@babel/preset-env": "^7.18.2",
|
||||
"@babel/preset-typescript": "^7.17.12",
|
||||
"@discordjs/ts-docgen": "^0.4.1",
|
||||
"@types/jest": "^28.1.0",
|
||||
"@discordjs/scripts": "workspace:^",
|
||||
"@types/node": "^16.11.38",
|
||||
"@typescript-eslint/eslint-plugin": "^5.27.0",
|
||||
"@typescript-eslint/parser": "^5.27.0",
|
||||
"babel-plugin-transform-typescript-metadata": "^0.3.2",
|
||||
"eslint": "^8.17.0",
|
||||
"eslint-config-marine": "^9.4.1",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"jest": "^28.1.0",
|
||||
"prettier": "^2.6.2",
|
||||
"tsup": "^6.0.1",
|
||||
"typedoc": "^0.22.17",
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import { runGenerator } from '@discordjs/ts-docgen';
|
||||
|
||||
runGenerator({
|
||||
existingOutput: 'docs/typedoc-out.json',
|
||||
custom: 'docs/index.yml',
|
||||
output: 'docs/docs.json',
|
||||
});
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
import { ComponentBuilder } from './Component';
|
||||
import { createComponentBuilder } from './Components';
|
||||
import type { ButtonBuilder, SelectMenuBuilder, TextInputBuilder } from '..';
|
||||
import { normalizeArray, type RestOrArray } from '../util/normalizeArray';
|
||||
|
||||
export type MessageComponentBuilder =
|
||||
| MessageActionRowComponentBuilder
|
||||
@@ -38,8 +39,8 @@ export class ActionRowBuilder<T extends AnyComponentBuilder> extends ComponentBu
|
||||
* @param components The components to add to this action row.
|
||||
* @returns
|
||||
*/
|
||||
public addComponents(components: T[]) {
|
||||
this.components.push(...components);
|
||||
public addComponents(...components: RestOrArray<T>) {
|
||||
this.components.push(...normalizeArray(components));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -47,8 +48,8 @@ export class ActionRowBuilder<T extends AnyComponentBuilder> extends ComponentBu
|
||||
* Sets the components in this action row
|
||||
* @param components The components to set this row to
|
||||
*/
|
||||
public setComponents(components: T[]) {
|
||||
this.components.splice(0, this.components.length, ...components);
|
||||
public setComponents(...components: RestOrArray<T>) {
|
||||
this.components.splice(0, this.components.length, ...normalizeArray(components));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { APISelectMenuComponent, APISelectMenuOption } from 'discord-api-types/v10';
|
||||
import { UnsafeSelectMenuBuilder } from './UnsafeSelectMenu';
|
||||
import { UnsafeSelectMenuOptionBuilder } from './UnsafeSelectMenuOption';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
|
||||
import {
|
||||
customIdValidator,
|
||||
disabledValidator,
|
||||
@@ -35,7 +36,8 @@ export class SelectMenuBuilder extends UnsafeSelectMenuBuilder {
|
||||
return super.setDisabled(disabledValidator.parse(disabled));
|
||||
}
|
||||
|
||||
public override addOptions(options: (UnsafeSelectMenuOptionBuilder | APISelectMenuOption)[]) {
|
||||
public override addOptions(...options: RestOrArray<UnsafeSelectMenuOptionBuilder | APISelectMenuOption>) {
|
||||
options = normalizeArray(options);
|
||||
optionsLengthValidator.parse(this.options.length + options.length);
|
||||
this.options.push(
|
||||
...options.map((option) =>
|
||||
@@ -47,7 +49,8 @@ export class SelectMenuBuilder extends UnsafeSelectMenuBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public override setOptions(options: (UnsafeSelectMenuOptionBuilder | APISelectMenuOption)[]) {
|
||||
public override setOptions(...options: RestOrArray<UnsafeSelectMenuOptionBuilder | APISelectMenuOption>) {
|
||||
options = normalizeArray(options);
|
||||
optionsLengthValidator.parse(options.length);
|
||||
this.options.splice(
|
||||
0,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { APISelectMenuOption, ComponentType, type APISelectMenuComponent } from 'discord-api-types/v10';
|
||||
import { UnsafeSelectMenuOptionBuilder } from './UnsafeSelectMenuOption';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
|
||||
import { ComponentBuilder } from '../Component';
|
||||
|
||||
/**
|
||||
@@ -67,9 +68,9 @@ export class UnsafeSelectMenuBuilder extends ComponentBuilder<APISelectMenuCompo
|
||||
* @param options The options to add to this select menu
|
||||
* @returns
|
||||
*/
|
||||
public addOptions(options: (UnsafeSelectMenuOptionBuilder | APISelectMenuOption)[]) {
|
||||
public addOptions(...options: RestOrArray<UnsafeSelectMenuOptionBuilder | APISelectMenuOption>) {
|
||||
this.options.push(
|
||||
...options.map((option) =>
|
||||
...normalizeArray(options).map((option) =>
|
||||
option instanceof UnsafeSelectMenuOptionBuilder ? option : new UnsafeSelectMenuOptionBuilder(option),
|
||||
),
|
||||
);
|
||||
@@ -80,11 +81,11 @@ export class UnsafeSelectMenuBuilder extends ComponentBuilder<APISelectMenuCompo
|
||||
* Sets the options on this select menu
|
||||
* @param options The options to set on this select menu
|
||||
*/
|
||||
public setOptions(options: (UnsafeSelectMenuOptionBuilder | APISelectMenuOption)[]) {
|
||||
public setOptions(...options: RestOrArray<UnsafeSelectMenuOptionBuilder | APISelectMenuOption>) {
|
||||
this.options.splice(
|
||||
0,
|
||||
this.options.length,
|
||||
...options.map((option) =>
|
||||
...normalizeArray(options).map((option) =>
|
||||
option instanceof UnsafeSelectMenuOptionBuilder ? option : new UnsafeSelectMenuOptionBuilder(option),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -45,3 +45,4 @@ export * from './interactions/contextMenuCommands/ContextMenuCommandBuilder';
|
||||
export * from './util/jsonEncodable';
|
||||
export * from './util/equatable';
|
||||
export * from './util/componentUtil';
|
||||
export * from './util/normalizeArray';
|
||||
|
||||
@@ -4,6 +4,7 @@ import type {
|
||||
APIModalInteractionResponseCallbackData,
|
||||
} from 'discord-api-types/v10';
|
||||
import { ActionRowBuilder, createComponentBuilder, JSONEncodable, ModalActionRowComponentBuilder } from '../../index';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
|
||||
|
||||
export class UnsafeModalBuilder implements JSONEncodable<APIModalInteractionResponseCallbackData> {
|
||||
public readonly data: Partial<APIModalInteractionResponseCallbackData>;
|
||||
@@ -38,13 +39,12 @@ export class UnsafeModalBuilder implements JSONEncodable<APIModalInteractionResp
|
||||
* @param components The components to add to this modal
|
||||
*/
|
||||
public addComponents(
|
||||
components: (
|
||||
| ActionRowBuilder<ModalActionRowComponentBuilder>
|
||||
| APIActionRowComponent<APIModalActionRowComponent>
|
||||
)[],
|
||||
...components: RestOrArray<
|
||||
ActionRowBuilder<ModalActionRowComponentBuilder> | APIActionRowComponent<APIModalActionRowComponent>
|
||||
>
|
||||
) {
|
||||
this.components.push(
|
||||
...components.map((component) =>
|
||||
...normalizeArray(components).map((component) =>
|
||||
component instanceof ActionRowBuilder
|
||||
? component
|
||||
: new ActionRowBuilder<ModalActionRowComponentBuilder>(component),
|
||||
@@ -57,8 +57,8 @@ export class UnsafeModalBuilder implements JSONEncodable<APIModalInteractionResp
|
||||
* Sets the components in this modal
|
||||
* @param components The components to set this modal to
|
||||
*/
|
||||
public setComponents(components: ActionRowBuilder<ModalActionRowComponentBuilder>[]) {
|
||||
this.components.splice(0, this.components.length, ...components);
|
||||
public setComponents(...components: RestOrArray<ActionRowBuilder<ModalActionRowComponentBuilder>>) {
|
||||
this.components.splice(0, this.components.length, ...normalizeArray(components));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,17 +12,19 @@ import {
|
||||
validateFieldLength,
|
||||
} from './Assertions';
|
||||
import { EmbedAuthorOptions, EmbedFooterOptions, RGBTuple, UnsafeEmbedBuilder } from './UnsafeEmbed';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
|
||||
|
||||
/**
|
||||
* Represents a validated embed in a message (image/video preview, rich embed, etc.)
|
||||
*/
|
||||
export class EmbedBuilder extends UnsafeEmbedBuilder {
|
||||
public override addFields(fields: APIEmbedField[]): this {
|
||||
public override addFields(...fields: RestOrArray<APIEmbedField>): this {
|
||||
fields = normalizeArray(fields);
|
||||
// Ensure adding these fields won't exceed the 25 field limit
|
||||
validateFieldLength(fields.length, this.data.fields);
|
||||
|
||||
// Data assertions
|
||||
return super.addFields(embedFieldsArrayPredicate.parse(fields));
|
||||
return super.addFields(...embedFieldsArrayPredicate.parse(fields));
|
||||
}
|
||||
|
||||
public override spliceFields(index: number, deleteCount: number, ...fields: APIEmbedField[]): this {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { APIEmbed, APIEmbedAuthor, APIEmbedField, APIEmbedFooter, APIEmbedImage } from 'discord-api-types/v10';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
|
||||
|
||||
export type RGBTuple = [red: number, green: number, blue: number];
|
||||
|
||||
@@ -44,7 +45,8 @@ export class UnsafeEmbedBuilder {
|
||||
*
|
||||
* @param fields The fields to add
|
||||
*/
|
||||
public addFields(fields: APIEmbedField[]): this {
|
||||
public addFields(...fields: RestOrArray<APIEmbedField>): this {
|
||||
fields = normalizeArray(fields);
|
||||
if (this.data.fields) this.data.fields.push(...fields);
|
||||
else this.data.fields = fields;
|
||||
return this;
|
||||
@@ -67,8 +69,8 @@ export class UnsafeEmbedBuilder {
|
||||
* Sets the embed's fields (max 25).
|
||||
* @param fields The fields to set
|
||||
*/
|
||||
public setFields(fields: APIEmbedField[]) {
|
||||
this.spliceFields(0, this.data.fields?.length ?? 0, ...fields);
|
||||
public setFields(...fields: RestOrArray<APIEmbedField>) {
|
||||
this.spliceFields(0, this.data.fields?.length ?? 0, ...normalizeArray(fields));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
6
packages/builders/src/util/normalizeArray.ts
Normal file
6
packages/builders/src/util/normalizeArray.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export function normalizeArray<T>(arr: RestOrArray<T>): T[] {
|
||||
if (Array.isArray(arr[0])) return arr[0];
|
||||
return arr as T[];
|
||||
}
|
||||
|
||||
export type RestOrArray<T> = T[] | [T[]];
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"releaseCommitMessageFormat": "chore(Release): publish"
|
||||
}
|
||||
@@ -30,9 +30,13 @@ pnpm add @discordjs/collection
|
||||
|
||||
- [Website](https://discord.js.org/) ([source](https://github.com/discordjs/website))
|
||||
- [Documentation](https://discord.js.org/#/docs/collection)
|
||||
- [Guide](https://discordjs.guide/) ([source](https://github.com/discordjs/guide))
|
||||
See also the [Update Guide](https://discordjs.guide/additional-info/changes-in-v13.html), including updated and removed items in the library.
|
||||
- [discord.js Discord server](https://discord.gg/djs)
|
||||
- [Discord API Discord server](https://discord.gg/discord-api)
|
||||
- [GitHub](https://github.com/discordjs/discord.js/tree/main/packages/collection)
|
||||
- [npm](https://www.npmjs.com/package/@discordjs/collection)
|
||||
- [Related libraries](https://discord.com/developers/docs/topics/community-resources#libraries)
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import Collection from '../src';
|
||||
|
||||
type TestCollection = Collection<string, number>;
|
||||
@@ -247,7 +248,7 @@ test('random select from a collection', () => {
|
||||
const chars = 'abcdefghijklmnopqrstuvwxyz';
|
||||
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26];
|
||||
|
||||
for (let i = 0; i < chars.length; i++) coll.set(chars[i], numbers[i]);
|
||||
for (let i = 0; i < chars.length; i++) coll.set(chars[i]!, numbers[i]!);
|
||||
|
||||
const random = coll.random(5);
|
||||
expect(random.length === 5).toBeTruthy();
|
||||
@@ -357,7 +358,7 @@ describe('hasAny() tests', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('reverse() tests', () => {
|
||||
test('reverse() tests', () => {
|
||||
const coll = new Collection();
|
||||
coll.set('a', 1);
|
||||
coll.set('b', 2);
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
/**
|
||||
* @type {import('@babel/core').TransformOptions}
|
||||
*/
|
||||
module.exports = {
|
||||
parserOpts: { strictMode: true },
|
||||
sourceMaps: 'inline',
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
targets: { node: 'current' },
|
||||
modules: 'commonjs',
|
||||
},
|
||||
],
|
||||
'@babel/preset-typescript',
|
||||
],
|
||||
};
|
||||
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* @type {import('@jest/types').Config.InitialOptions}
|
||||
*/
|
||||
module.exports = {
|
||||
testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'],
|
||||
testEnvironment: 'node',
|
||||
collectCoverage: true,
|
||||
collectCoverageFrom: ['src/**/*.ts'],
|
||||
coverageDirectory: 'coverage',
|
||||
coverageReporters: ['text', 'lcov', 'clover'],
|
||||
};
|
||||
@@ -1,15 +1,14 @@
|
||||
{
|
||||
"name": "@discordjs/collection",
|
||||
"version": "0.7.0",
|
||||
"version": "0.8.0-dev",
|
||||
"description": "Utility data structure used in discord.js",
|
||||
"scripts": {
|
||||
"test": "jest --pass-with-no-tests",
|
||||
"build": "tsup",
|
||||
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"docs": "typedoc --json docs/typedoc-out.json src/index.ts && node scripts/docs.mjs",
|
||||
"docs": "typedoc --json docs/typedoc-out.json src/index.ts && ts-docgen -i docs/typedoc-out.json -c docs/index.yml -o docs/docs.json",
|
||||
"prepublishOnly": "yarn build && yarn lint && yarn test",
|
||||
"changelog": "git cliff --prepend ./CHANGELOG.md -l -c ./cliff.toml -r ../../ --include-path 'packages/collection/*'"
|
||||
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/collection/*'"
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.mjs",
|
||||
@@ -48,11 +47,7 @@
|
||||
},
|
||||
"homepage": "https://discord.js.org",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.18.2",
|
||||
"@babel/preset-env": "^7.18.2",
|
||||
"@babel/preset-typescript": "^7.17.12",
|
||||
"@discordjs/ts-docgen": "^0.4.1",
|
||||
"@types/jest": "^28.1.0",
|
||||
"@discordjs/scripts": "workspace:^",
|
||||
"@types/node": "^16.11.38",
|
||||
"@typescript-eslint/eslint-plugin": "^5.27.0",
|
||||
"@typescript-eslint/parser": "^5.27.0",
|
||||
@@ -60,7 +55,6 @@
|
||||
"eslint-config-marine": "^9.4.1",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"jest": "^28.1.0",
|
||||
"prettier": "^2.6.2",
|
||||
"tsup": "^6.0.1",
|
||||
"typedoc": "^0.22.17",
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import { runGenerator } from '@discordjs/ts-docgen';
|
||||
|
||||
runGenerator({
|
||||
existingOutput: 'docs/typedoc-out.json',
|
||||
custom: 'docs/index.yml',
|
||||
output: 'docs/docs.json',
|
||||
});
|
||||
@@ -107,7 +107,7 @@ client.login('token');
|
||||
See also the [Update Guide](https://discordjs.guide/additional-info/changes-in-v13.html), including updated and removed items in the library.
|
||||
- [discord.js Discord server](https://discord.gg/djs)
|
||||
- [Discord API Discord server](https://discord.gg/discord-api)
|
||||
- [GitHub](https://github.com/discordjs/discord.js)
|
||||
- [GitHub](https://github.com/discordjs/discord.js/tree/main/packages/discord.js)
|
||||
- [npm](https://www.npmjs.com/package/discord.js)
|
||||
- [Related libraries](https://discord.com/developers/docs/topics/community-resources#libraries)
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"docs": "docgen --source ./src --custom ./docs/index.yml --root ../../ --output ./docs/docs.json",
|
||||
"docs:test": "docgen --source ./src --custom ./docs/index.yml --root ../../",
|
||||
"prepublishOnly": "yarn lint && yarn test",
|
||||
"changelog": "git cliff --prepend ./CHANGELOG.md -l -c ./cliff.toml -r ../../ --include-path 'packages/discord.js/*'"
|
||||
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/discord.js/*'"
|
||||
},
|
||||
"main": "./src/index.js",
|
||||
"types": "./typings/index.d.ts",
|
||||
|
||||
@@ -220,13 +220,8 @@ class WebSocketManager extends EventEmitter {
|
||||
|
||||
this.shardQueue.add(shard);
|
||||
|
||||
if (shard.sessionId) {
|
||||
this.debug(`Session id is present, attempting an immediate reconnect...`, shard);
|
||||
this.reconnect();
|
||||
} else {
|
||||
shard.destroy({ reset: true, emit: false, log: false });
|
||||
this.reconnect();
|
||||
}
|
||||
if (shard.sessionId) this.debug(`Session id is present, attempting an immediate reconnect...`, shard);
|
||||
this.reconnect();
|
||||
});
|
||||
|
||||
shard.on(ShardEvents.InvalidSession, () => {
|
||||
|
||||
@@ -84,6 +84,13 @@ class WebSocketShard extends EventEmitter {
|
||||
*/
|
||||
this.lastHeartbeatAcked = true;
|
||||
|
||||
/**
|
||||
* Used to prevent calling {@link WebSocketShard#event:close} twice while closing or terminating the WebSocket.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.closeEmitted = false;
|
||||
|
||||
/**
|
||||
* Contains the rate limit queue and metadata
|
||||
* @name WebSocketShard#ratelimit
|
||||
@@ -129,6 +136,14 @@ class WebSocketShard extends EventEmitter {
|
||||
*/
|
||||
Object.defineProperty(this, 'helloTimeout', { value: null, writable: true });
|
||||
|
||||
/**
|
||||
* The WebSocket timeout.
|
||||
* @name WebSocketShard#wsCloseTimeout
|
||||
* @type {?NodeJS.Timeout}
|
||||
* @private
|
||||
*/
|
||||
Object.defineProperty(this, 'wsCloseTimeout', { value: null, writable: true });
|
||||
|
||||
/**
|
||||
* If the manager attached its event handlers on the shard
|
||||
* @name WebSocketShard#eventsAttached
|
||||
@@ -256,7 +271,8 @@ class WebSocketShard extends EventEmitter {
|
||||
|
||||
this.connectedAt = Date.now();
|
||||
|
||||
const ws = (this.connection = WebSocket.create(gateway, wsQuery));
|
||||
// Adding a handshake timeout to just make sure no zombie connection appears.
|
||||
const ws = (this.connection = WebSocket.create(gateway, wsQuery, { handshakeTimeout: 30_000 }));
|
||||
ws.onopen = this.onOpen.bind(this);
|
||||
ws.onmessage = this.onMessage.bind(this);
|
||||
ws.onerror = this.onError.bind(this);
|
||||
@@ -343,21 +359,35 @@ class WebSocketShard extends EventEmitter {
|
||||
* @private
|
||||
*/
|
||||
onClose(event) {
|
||||
this.closeEmitted = true;
|
||||
if (this.sequence !== -1) this.closeSequence = this.sequence;
|
||||
this.sequence = -1;
|
||||
this.setHeartbeatTimer(-1);
|
||||
this.setHelloTimeout(-1);
|
||||
// Clearing the WebSocket close timeout as close was emitted.
|
||||
this.setWsCloseTimeout(-1);
|
||||
// If we still have a connection object, clean up its listeners
|
||||
if (this.connection) this._cleanupConnection();
|
||||
this.status = Status.DISCONNECTED;
|
||||
this.emitClose(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is responsible to emit close event for this shard.
|
||||
* This method helps the shard reconnect.
|
||||
* @param {CloseEvent} [event] Close event that was received
|
||||
*/
|
||||
emitClose(
|
||||
event = {
|
||||
code: 1011,
|
||||
reason: 'INTERNAL_ERROR',
|
||||
wasClean: false,
|
||||
},
|
||||
) {
|
||||
this.debug(`[CLOSE]
|
||||
Event Code: ${event.code}
|
||||
Clean : ${event.wasClean}
|
||||
Reason : ${event.reason ?? 'No reason received'}`);
|
||||
|
||||
this.setHeartbeatTimer(-1);
|
||||
this.setHelloTimeout(-1);
|
||||
// If we still have a connection object, clean up its listeners
|
||||
if (this.connection) this._cleanupConnection();
|
||||
|
||||
this.status = Status.Disconnected;
|
||||
|
||||
/**
|
||||
* Emitted when a shard's WebSocket closes.
|
||||
* @private
|
||||
@@ -366,7 +396,6 @@ class WebSocketShard extends EventEmitter {
|
||||
*/
|
||||
this.emit(ShardEvents.Close, event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called whenever a packet is received.
|
||||
* @param {Object} packet The received packet
|
||||
@@ -526,6 +555,47 @@ class WebSocketShard extends EventEmitter {
|
||||
}, 20_000).unref();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the WebSocket Close timeout.
|
||||
* This method is responsible for detecting any zombie connections if the WebSocket fails to close properly.
|
||||
* @param {number} [time] If set to -1, it will clear the timeout
|
||||
* @private
|
||||
*/
|
||||
setWsCloseTimeout(time) {
|
||||
if (this.wsCloseTimeout) {
|
||||
this.debug('[WebSocket] Clearing the close timeout.');
|
||||
clearTimeout(this.wsCloseTimeout);
|
||||
}
|
||||
if (time === -1) {
|
||||
this.wsCloseTimeout = null;
|
||||
return;
|
||||
}
|
||||
this.wsCloseTimeout = setTimeout(() => {
|
||||
this.setWsCloseTimeout(-1);
|
||||
this.debug(`[WebSocket] Close Emitted: ${this.closeEmitted}`);
|
||||
// Check if close event was emitted.
|
||||
if (this.closeEmitted) {
|
||||
this.debug(
|
||||
`[WebSocket] was closed. | WS State: ${
|
||||
CONNECTION_STATE[this.connection?.readyState ?? WebSocket.CLOSED]
|
||||
} | Close Emitted: ${this.closeEmitted}`,
|
||||
);
|
||||
// Setting the variable false to check for zombie connections.
|
||||
this.closeEmitted = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.debug(
|
||||
// eslint-disable-next-line max-len
|
||||
`[WebSocket] did not close properly, assuming a zombie connection.\nEmitting close and reconnecting again.`,
|
||||
);
|
||||
|
||||
this.emitClose();
|
||||
// Setting the variable false to check for zombie connections.
|
||||
this.closeEmitted = false;
|
||||
}, time).unref();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the heartbeat timer for this shard.
|
||||
* @param {number} time If -1, clears the interval, any other number sets an interval
|
||||
@@ -567,7 +637,7 @@ class WebSocketShard extends EventEmitter {
|
||||
Connection State: ${this.connection ? CONNECTION_STATE[this.connection.readyState] : 'No Connection??'}`,
|
||||
);
|
||||
|
||||
this.destroy({ closeCode: 4009, reset: true });
|
||||
this.destroy({ reset: true, closeCode: 4009 });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -716,11 +786,17 @@ class WebSocketShard extends EventEmitter {
|
||||
this.setHeartbeatTimer(-1);
|
||||
this.setHelloTimeout(-1);
|
||||
|
||||
this.debug(
|
||||
`[WebSocket] Destroy: Attempting to close the WebSocket. | WS State: ${
|
||||
CONNECTION_STATE[this.connection?.readyState ?? WebSocket.CLOSED]
|
||||
}`,
|
||||
);
|
||||
// Step 1: Close the WebSocket connection, if any, otherwise, emit DESTROYED
|
||||
if (this.connection) {
|
||||
// If the connection is currently opened, we will (hopefully) receive close
|
||||
if (this.connection.readyState === WebSocket.OPEN) {
|
||||
this.connection.close(closeCode);
|
||||
this.debug(`[WebSocket] Close: Tried closing. | WS State: ${CONNECTION_STATE[this.connection.readyState]}`);
|
||||
} else {
|
||||
// Connection is not OPEN
|
||||
this.debug(`WS State: ${CONNECTION_STATE[this.connection.readyState]}`);
|
||||
@@ -729,8 +805,13 @@ class WebSocketShard extends EventEmitter {
|
||||
// Attempt to close the connection just in case
|
||||
try {
|
||||
this.connection.close(closeCode);
|
||||
} catch {
|
||||
// No-op
|
||||
} catch (err) {
|
||||
this.debug(
|
||||
`[WebSocket] Close: Something went wrong while closing the WebSocket: ${
|
||||
err.message || err
|
||||
}. Forcefully terminating the connection | WS State: ${CONNECTION_STATE[this.connection.readyState]}`,
|
||||
);
|
||||
this.connection.terminate();
|
||||
}
|
||||
// Emit the destroyed event if needed
|
||||
if (emit) this._emitDestroyed();
|
||||
@@ -740,11 +821,20 @@ class WebSocketShard extends EventEmitter {
|
||||
this._emitDestroyed();
|
||||
}
|
||||
|
||||
if (this.connection?.readyState === WebSocket.CLOSING || this.connection?.readyState === WebSocket.CLOSED) {
|
||||
this.closeEmitted = false;
|
||||
this.debug(
|
||||
`[WebSocket] Adding a WebSocket close timeout to ensure a correct WS reconnect.
|
||||
Timeout: ${this.manager.client.options.closeTimeout}ms`,
|
||||
);
|
||||
this.setWsCloseTimeout(this.manager.client.options.closeTimeout);
|
||||
}
|
||||
|
||||
// Step 2: Null the connection object
|
||||
this.connection = null;
|
||||
|
||||
// Step 3: Set the shard status to Disconnected
|
||||
this.status = Status.Disconnected;
|
||||
// Step 3: Set the shard status to DISCONNECTED
|
||||
this.status = Status.DISCONNECTED;
|
||||
|
||||
// Step 4: Cache the old sequence (use to attempt a resume)
|
||||
if (this.sequence !== -1) this.closeSequence = this.sequence;
|
||||
|
||||
@@ -123,6 +123,7 @@ exports.InviteStageInstance = require('./structures/InviteStageInstance');
|
||||
exports.InviteGuild = require('./structures/InviteGuild');
|
||||
exports.Message = require('./structures/Message').Message;
|
||||
exports.Attachment = require('./structures/Attachment');
|
||||
exports.AttachmentBuilder = require('./structures/AttachmentBuilder');
|
||||
exports.ModalBuilder = require('./structures/ModalBuilder');
|
||||
exports.MessageCollector = require('./structures/MessageCollector');
|
||||
exports.MessageComponentInteraction = require('./structures/MessageComponentInteraction');
|
||||
|
||||
@@ -99,7 +99,7 @@ class GuildChannelManager extends CachedManager {
|
||||
/**
|
||||
* Options used to create a new channel in a guild.
|
||||
* @typedef {CategoryCreateChannelOptions} GuildChannelCreateOptions
|
||||
* @property {CategoryChannelResolvable} [parent] Parent of the new channel
|
||||
* @property {?CategoryChannelResolvable} [parent] Parent of the new channel
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -201,7 +201,7 @@ class GuildChannelManager extends CachedManager {
|
||||
* @property {string} [name] The name of the channel
|
||||
* @property {ChannelType} [type] The type of the channel (only conversion between text and news is supported)
|
||||
* @property {number} [position] The position of the channel
|
||||
* @property {string} [topic] The topic of the text channel
|
||||
* @property {?string} [topic] The topic of the text channel
|
||||
* @property {boolean} [nsfw] Whether the channel is NSFW
|
||||
* @property {number} [bitrate] The bitrate of the voice channel
|
||||
* @property {number} [userLimit] The user limit of the voice channel
|
||||
|
||||
@@ -84,7 +84,7 @@ class GuildManager extends CachedManager {
|
||||
* @property {Snowflake|number} [parentId] The parent id for this channel
|
||||
* @property {ChannelType|number} [type] The type of the channel
|
||||
* @property {string} name The name of the channel
|
||||
* @property {string} [topic] The topic of the text channel
|
||||
* @property {?string} [topic] The topic of the text channel
|
||||
* @property {boolean} [nsfw] Whether the channel is NSFW
|
||||
* @property {number} [bitrate] The bitrate of the voice channel
|
||||
* @property {number} [userLimit] The user limit of the channel
|
||||
@@ -137,22 +137,24 @@ class GuildManager extends CachedManager {
|
||||
return super.resolveId(guild);
|
||||
}
|
||||
|
||||
/* eslint-disable max-len */
|
||||
/**
|
||||
* Options used to create a guild.
|
||||
* @typedef {Object} GuildCreateOptions
|
||||
* @property {Snowflake|number} [afkChannelId] The AFK channel's id
|
||||
* @property {number} [afkTimeout] The AFK timeout in seconds
|
||||
* @property {PartialChannelData[]} [channels=[]] The channels for this guild
|
||||
* @property {DefaultMessageNotificationLevel|number} [defaultMessageNotifications] The default message notifications
|
||||
* @property {GuildDefaultMessageNotificationLevel|number} [defaultMessageNotifications] The default message notifications
|
||||
* for the guild
|
||||
* @property {ExplicitContentFilterLevel} [explicitContentFilter] The explicit content filter level for the guild
|
||||
* @property {GuildExplicitContentFilterLevel} [explicitContentFilter] The explicit content filter level for the guild
|
||||
* @property {?(BufferResolvable|Base64Resolvable)} [icon=null] The icon for the guild
|
||||
* @property {PartialRoleData[]} [roles=[]] The roles for this guild,
|
||||
* the first element of this array is used to change properties of the guild's everyone role.
|
||||
* @property {Snowflake|number} [systemChannelId] The system channel's id
|
||||
* @property {SystemChannelFlagsResolvable} [systemChannelFlags] The flags of the system channel
|
||||
* @property {VerificationLevel} [verificationLevel] The verification level for the guild
|
||||
* @property {GuildVerificationLevel} [verificationLevel] The verification level for the guild
|
||||
*/
|
||||
/* eslint-enable max-len */
|
||||
|
||||
/**
|
||||
* Creates a guild.
|
||||
|
||||
@@ -206,6 +206,15 @@ class GuildMemberManager extends CachedManager {
|
||||
return this._fetchMany(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the client user as a GuildMember of the guild.
|
||||
* @param {BaseFetchOptions} [options] The options for fetching the member
|
||||
* @returns {Promise<GuildMember>}
|
||||
*/
|
||||
fetchMe(options) {
|
||||
return this.fetch({ ...options, user: this.client.user.id });
|
||||
}
|
||||
|
||||
/**
|
||||
* Options used for searching guild members.
|
||||
* @typedef {Object} GuildSearchMembersOptions
|
||||
|
||||
@@ -43,7 +43,7 @@ class GuildScheduledEventManager extends CachedManager {
|
||||
* @property {DateResolvable} scheduledStartTime The time to schedule the event at
|
||||
* @property {DateResolvable} [scheduledEndTime] The time to end the event at
|
||||
* <warn>This is required if `entityType` is {@link GuildScheduledEventEntityType.External}</warn>
|
||||
* @property {PrivacyLevel|number} privacyLevel The privacy level of the guild scheduled event
|
||||
* @property {GuildScheduledEventPrivacyLevel|number} privacyLevel The privacy level of the guild scheduled event
|
||||
* @property {GuildScheduledEventEntityType|number} entityType The scheduled entity type of the event
|
||||
* @property {string} [description] The description of the guild scheduled event
|
||||
* @property {GuildVoiceChannelResolvable} [channel] The channel of the guild scheduled event
|
||||
@@ -167,7 +167,7 @@ class GuildScheduledEventManager extends CachedManager {
|
||||
* @property {string} [name] The name of the guild scheduled event
|
||||
* @property {DateResolvable} [scheduledStartTime] The time to schedule the event at
|
||||
* @property {DateResolvable} [scheduledEndTime] The time to end the event at
|
||||
* @property {PrivacyLevel|number} [privacyLevel] The privacy level of the guild scheduled event
|
||||
* @property {GuildScheduledEventPrivacyLevel|number} [privacyLevel] The privacy level of the guild scheduled event
|
||||
* @property {GuildScheduledEventEntityType|number} [entityType] The scheduled entity type of the event
|
||||
* @property {string} [description] The description of the guild scheduled event
|
||||
* @property {?GuildVoiceChannelResolvable} [channel] The channel of the guild scheduled event
|
||||
|
||||
@@ -41,7 +41,7 @@ class GuildStickerManager extends CachedManager {
|
||||
|
||||
/**
|
||||
* Creates a new custom sticker in the guild.
|
||||
* @param {BufferResolvable|Stream|FileOptions|Attachment} file The file for the sticker
|
||||
* @param {BufferResolvable|Stream|JSONEncodable<AttachmentPayload>} file The file for the sticker
|
||||
* @param {string} name The name for the sticker
|
||||
* @param {string} tags The Discord name of a unicode emoji representing the sticker's expression
|
||||
* @param {GuildStickerCreateOptions} [options] Options
|
||||
|
||||
@@ -30,7 +30,7 @@ class StageInstanceManager extends CachedManager {
|
||||
* Options used to create a stage instance.
|
||||
* @typedef {Object} StageInstanceCreateOptions
|
||||
* @property {string} topic The topic of the stage instance
|
||||
* @property {PrivacyLevel|number} [privacyLevel] The privacy level of the stage instance
|
||||
* @property {StageInstancePrivacyLevel|number} [privacyLevel] The privacy level of the stage instance
|
||||
* @property {boolean} [sendStartNotification] Whether to notify `@everyone` that the stage instance has started
|
||||
*/
|
||||
|
||||
@@ -101,7 +101,7 @@ class StageInstanceManager extends CachedManager {
|
||||
* Options used to edit an existing stage instance.
|
||||
* @typedef {Object} StageInstanceEditOptions
|
||||
* @property {string} [topic] The new topic of the stage instance
|
||||
* @property {PrivacyLevel|number} [privacyLevel] The new privacy level of the stage instance
|
||||
* @property {StageInstancePrivacyLevel|number} [privacyLevel] The new privacy level of the stage instance
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,6 +37,15 @@ class ThreadMemberManager extends CachedManager {
|
||||
return member;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the client user as a ThreadMember of the thread.
|
||||
* @param {BaseFetchOptions} [options] The options for fetching the member
|
||||
* @returns {Promise<ThreadMember>}
|
||||
*/
|
||||
fetchMe(options) {
|
||||
return this.fetch({ ...options, member: this.client.user.id });
|
||||
}
|
||||
|
||||
/**
|
||||
* The client user as a ThreadMember of this ThreadChannel
|
||||
* @type {?ThreadMember}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const { ActionRowBuilder: BuildersActionRow, ComponentBuilder } = require('@discordjs/builders');
|
||||
const { ActionRowBuilder: BuildersActionRow, ComponentBuilder, isJSONEncodable } = require('@discordjs/builders');
|
||||
const Components = require('../util/Components');
|
||||
const Transformers = require('../util/Transformers');
|
||||
|
||||
@@ -15,6 +15,19 @@ class ActionRowBuilder extends BuildersActionRow {
|
||||
components: components?.map(c => (c instanceof ComponentBuilder ? c : Components.createComponentBuilder(c))),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new action row builder from JSON data
|
||||
* @param {JSONEncodable<APIActionRowComponent<APIActionRowComponentTypes>>
|
||||
* |APIActionRowComponent<APIActionRowComponentTypes>} other The other data
|
||||
* @returns {ActionRowBuilder}
|
||||
*/
|
||||
static from(other) {
|
||||
if (isJSONEncodable(other)) {
|
||||
return new this(other.toJSON());
|
||||
}
|
||||
return new this(other);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ActionRowBuilder;
|
||||
|
||||
@@ -3,74 +3,26 @@
|
||||
const Util = require('../util/Util');
|
||||
|
||||
/**
|
||||
* Represents an attachment.
|
||||
* @typedef {Object} AttachmentPayload
|
||||
* @property {?string} name The name of the attachment
|
||||
* @property {Stream|BufferResolvable} attachment The attachment in this payload
|
||||
* @property {?string} description The description of the attachment
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents an attachment
|
||||
*/
|
||||
class Attachment {
|
||||
/**
|
||||
* @param {BufferResolvable|Stream} attachment The file
|
||||
* @param {string} [name=null] The name of the file, if any
|
||||
* @param {APIAttachment} [data] Extra data
|
||||
*/
|
||||
constructor(attachment, name = null, data) {
|
||||
this.attachment = attachment;
|
||||
constructor({ url, filename, ...data }) {
|
||||
this.attachment = url;
|
||||
/**
|
||||
* The name of this attachment
|
||||
* @type {?string}
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = name;
|
||||
this.name = filename;
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the description of this attachment.
|
||||
* @param {string} description The description of the file
|
||||
* @returns {Attachment} This attachment
|
||||
*/
|
||||
setDescription(description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the file of this attachment.
|
||||
* @param {BufferResolvable|Stream} attachment The file
|
||||
* @param {string} [name=null] The name of the file, if any
|
||||
* @returns {Attachment} This attachment
|
||||
*/
|
||||
setFile(attachment, name = null) {
|
||||
this.attachment = attachment;
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of this attachment.
|
||||
* @param {string} name The name of the file
|
||||
* @returns {Attachment} This attachment
|
||||
*/
|
||||
setName(name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this attachment is a spoiler
|
||||
* @param {boolean} [spoiler=true] Whether the attachment should be marked as a spoiler
|
||||
* @returns {Attachment} This attachment
|
||||
*/
|
||||
setSpoiler(spoiler = true) {
|
||||
if (spoiler === this.spoiler) return this;
|
||||
|
||||
if (!spoiler) {
|
||||
while (this.spoiler) {
|
||||
this.name = this.name.slice('SPOILER_'.length);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
this.name = `SPOILER_${this.name}`;
|
||||
return this;
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
/**
|
||||
* The attachment's id
|
||||
@@ -164,8 +116,3 @@ class Attachment {
|
||||
}
|
||||
|
||||
module.exports = Attachment;
|
||||
|
||||
/**
|
||||
* @external APIAttachment
|
||||
* @see {@link https://discord.com/developers/docs/resources/channel#attachment-object}
|
||||
*/
|
||||
|
||||
110
packages/discord.js/src/structures/AttachmentBuilder.js
Normal file
110
packages/discord.js/src/structures/AttachmentBuilder.js
Normal file
@@ -0,0 +1,110 @@
|
||||
'use strict';
|
||||
|
||||
const Util = require('../util/Util');
|
||||
|
||||
/**
|
||||
* Represents an attachment builder
|
||||
*/
|
||||
class AttachmentBuilder {
|
||||
/**
|
||||
* @param {BufferResolvable|Stream} attachment The file
|
||||
* @param {APIAttachment} [data] Extra data
|
||||
*/
|
||||
constructor(attachment, data = {}) {
|
||||
/**
|
||||
* The file associated with this attachment.
|
||||
* @type {BufferResolvable|Stream}
|
||||
*/
|
||||
this.attachment = attachment;
|
||||
/**
|
||||
* The name of this attachment
|
||||
* @type {?string}
|
||||
*/
|
||||
this.name = data.name;
|
||||
/**
|
||||
* The description of the attachment
|
||||
* @type {?string}
|
||||
*/
|
||||
this.description = data.description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the description of this attachment.
|
||||
* @param {string} description The description of the file
|
||||
* @returns {AttachmentBuilder} This attachment
|
||||
*/
|
||||
setDescription(description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the file of this attachment.
|
||||
* @param {BufferResolvable|Stream} attachment The file
|
||||
* @returns {AttachmentBuilder} This attachment
|
||||
*/
|
||||
setFile(attachment) {
|
||||
this.attachment = attachment;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of this attachment.
|
||||
* @param {string} name The name of the file
|
||||
* @returns {AttachmentBuilder} This attachment
|
||||
*/
|
||||
setName(name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this attachment is a spoiler
|
||||
* @param {boolean} [spoiler=true] Whether the attachment should be marked as a spoiler
|
||||
* @returns {AttachmentBuilder} This attachment
|
||||
*/
|
||||
setSpoiler(spoiler = true) {
|
||||
if (spoiler === this.spoiler) return this;
|
||||
|
||||
if (!spoiler) {
|
||||
while (this.spoiler) {
|
||||
this.name = this.name.slice('SPOILER_'.length);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
this.name = `SPOILER_${this.name}`;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this attachment has been marked as a spoiler
|
||||
* @type {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get spoiler() {
|
||||
return Util.basename(this.name).startsWith('SPOILER_');
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return Util.flatten(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a new builder instance from a preexisting attachment structure.
|
||||
* @param {JSONEncodable<AttachmentPayload>} other The builder to construct a new instance from
|
||||
* @returns {AttachmentBuilder}
|
||||
*/
|
||||
static from(other) {
|
||||
return new AttachmentBuilder(other.attachment, {
|
||||
name: other.name,
|
||||
description: other.description,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AttachmentBuilder;
|
||||
|
||||
/**
|
||||
* @external APIAttachment
|
||||
* @see {@link https://discord.com/developers/docs/resources/channel#attachment-object}
|
||||
*/
|
||||
@@ -32,7 +32,7 @@ class AutocompleteInteraction extends Interaction {
|
||||
|
||||
/**
|
||||
* The invoked application command's type
|
||||
* @type {ApplicationCommandType.ChatInput}
|
||||
* @type {ApplicationCommandType}
|
||||
*/
|
||||
this.commandType = data.data.type;
|
||||
|
||||
|
||||
@@ -110,54 +110,6 @@ class Channel extends Base {
|
||||
return this.client.channels.fetch(this.id, { force });
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this channel is a {@link TextChannel}.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isText() {
|
||||
return this.type === ChannelType.GuildText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this channel is a {@link DMChannel}.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isDM() {
|
||||
return this.type === ChannelType.DM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this channel is a {@link VoiceChannel}.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isVoice() {
|
||||
return this.type === ChannelType.GuildVoice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this channel is a {@link PartialGroupDMChannel}.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isGroupDM() {
|
||||
return this.type === ChannelType.GroupDM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this channel is a {@link CategoryChannel}.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isCategory() {
|
||||
return this.type === ChannelType.GuildCategory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this channel is a {@link NewsChannel}.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isNews() {
|
||||
return this.type === ChannelType.GuildNews;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this channel is a {@link ThreadChannel}.
|
||||
* @returns {boolean}
|
||||
@@ -166,22 +118,6 @@ class Channel extends Base {
|
||||
return ThreadChannelTypes.includes(this.type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this channel is a {@link StageChannel}.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isStage() {
|
||||
return this.type === ChannelType.GuildStageVoice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this channel is a {@link DirectoryChannel}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isDirectory() {
|
||||
return this.type === ChannelType.GuildDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this channel is {@link TextBasedChannels text-based}.
|
||||
* @returns {boolean}
|
||||
|
||||
@@ -40,6 +40,12 @@ class CommandInteraction extends Interaction {
|
||||
*/
|
||||
this.commandType = data.data.type;
|
||||
|
||||
/**
|
||||
* The id of the guild the invoked application command is registered to
|
||||
* @type {?Snowflake}
|
||||
*/
|
||||
this.commandGuildId = data.data.guild_id ?? null;
|
||||
|
||||
/**
|
||||
* Whether the reply to this interaction has been deferred
|
||||
* @type {boolean}
|
||||
@@ -133,7 +139,7 @@ class CommandInteraction extends Interaction {
|
||||
if (attachments) {
|
||||
result.attachments = new Collection();
|
||||
for (const attachment of Object.values(attachments)) {
|
||||
const patched = new Attachment(attachment.url, attachment.filename, attachment);
|
||||
const patched = new Attachment(attachment);
|
||||
result.attachments.set(attachment.id, patched);
|
||||
}
|
||||
}
|
||||
@@ -189,7 +195,7 @@ class CommandInteraction extends Interaction {
|
||||
if (role) result.role = this.guild?.roles._add(role) ?? role;
|
||||
|
||||
const attachment = resolved.attachments?.[option.value];
|
||||
if (attachment) result.attachment = new Attachment(attachment.url, attachment.filename, attachment);
|
||||
if (attachment) result.attachment = new Attachment(attachment);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -248,7 +248,7 @@ class CommandInteractionOptionResolver {
|
||||
* Gets a message option.
|
||||
* @param {string} name The name of the option.
|
||||
* @param {boolean} [required=false] Whether to throw an error if the option is not found.
|
||||
* @returns {?(Message|APIMessage)}
|
||||
* @returns {?Message}
|
||||
* The value of the option, or null if not set and not required.
|
||||
*/
|
||||
getMessage(name, required = false) {
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
const { ApplicationCommandOptionType } = require('discord-api-types/v10');
|
||||
const CommandInteraction = require('./CommandInteraction');
|
||||
const CommandInteractionOptionResolver = require('./CommandInteractionOptionResolver');
|
||||
const { lazy } = require('../util/Util');
|
||||
|
||||
const getMessage = lazy(() => require('./Message').Message);
|
||||
|
||||
/**
|
||||
* Represents a context menu interaction.
|
||||
@@ -48,7 +51,9 @@ class ContextMenuCommandInteraction extends CommandInteraction {
|
||||
name: 'message',
|
||||
type: '_MESSAGE',
|
||||
value: target_id,
|
||||
message: this.channel?.messages._add(resolved.messages[target_id]) ?? resolved.messages[target_id],
|
||||
message:
|
||||
this.channel?.messages._add(resolved.messages[target_id]) ??
|
||||
new (getMessage())(this.client, resolved.messages[target_id]),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
const { Channel } = require('./Channel');
|
||||
|
||||
/**
|
||||
* Represents a channel that displays a directory of guilds
|
||||
* Represents a channel that displays a directory of guilds.
|
||||
* @extends {Channel}
|
||||
*/
|
||||
class DirectoryChannel extends Channel {
|
||||
_patch(data) {
|
||||
|
||||
@@ -237,7 +237,7 @@ class Guild extends AnonymousGuild {
|
||||
if ('mfa_level' in data) {
|
||||
/**
|
||||
* The required MFA level for this guild
|
||||
* @type {MFALevel}
|
||||
* @type {GuildMFALevel}
|
||||
*/
|
||||
this.mfaLevel = data.mfa_level;
|
||||
}
|
||||
@@ -713,12 +713,13 @@ class Guild extends AnonymousGuild {
|
||||
return new GuildAuditLogs(this, data);
|
||||
}
|
||||
|
||||
/* eslint-disable max-len */
|
||||
/**
|
||||
* The data for editing a guild.
|
||||
* @typedef {Object} GuildEditData
|
||||
* @property {string} [name] The name of the guild
|
||||
* @property {?(VerificationLevel|number)} [verificationLevel] The verification level of the guild
|
||||
* @property {?(ExplicitContentFilterLevel|number)} [explicitContentFilter] The level of the explicit content filter
|
||||
* @property {?(GuildVerificationLevel|number)} [verificationLevel] The verification level of the guild
|
||||
* @property {?(GuildExplicitContentFilterLevel|number)} [explicitContentFilter] The level of the explicit content filter
|
||||
* @property {?VoiceChannelResolvable} [afkChannel] The AFK channel of the guild
|
||||
* @property {?TextChannelResolvable} [systemChannel] The system channel of the guild
|
||||
* @property {number} [afkTimeout] The AFK timeout of the guild
|
||||
@@ -727,7 +728,7 @@ class Guild extends AnonymousGuild {
|
||||
* @property {?(BufferResolvable|Base64Resolvable)} [splash] The invite splash image of the guild
|
||||
* @property {?(BufferResolvable|Base64Resolvable)} [discoverySplash] The discovery splash image of the guild
|
||||
* @property {?(BufferResolvable|Base64Resolvable)} [banner] The banner of the guild
|
||||
* @property {?(DefaultMessageNotificationLevel|number)} [defaultMessageNotifications] The default message
|
||||
* @property {?(GuildDefaultMessageNotificationLevel|number)} [defaultMessageNotifications] The default message
|
||||
* notification level of the guild
|
||||
* @property {SystemChannelFlagsResolvable} [systemChannelFlags] The system channel flags of the guild
|
||||
* @property {?TextChannelResolvable} [rulesChannel] The rules channel of the guild
|
||||
@@ -737,6 +738,7 @@ class Guild extends AnonymousGuild {
|
||||
* @property {?string} [description] The discovery description of the guild
|
||||
* @property {GuildFeature[]} [features] The features of the guild
|
||||
*/
|
||||
/* eslint-enable max-len */
|
||||
|
||||
/**
|
||||
* Data that can be resolved to a Text Channel object. This can be:
|
||||
@@ -882,9 +884,10 @@ class Guild extends AnonymousGuild {
|
||||
return new WelcomeScreen(this, patchData);
|
||||
}
|
||||
|
||||
/* eslint-disable max-len */
|
||||
/**
|
||||
* Edits the level of the explicit content filter.
|
||||
* @param {?(ExplicitContentFilterLevel|number)} explicitContentFilter The new level of the explicit content filter
|
||||
* @param {?(GuildExplicitContentFilterLevel|number)} explicitContentFilter The new level of the explicit content filter
|
||||
* @param {string} [reason] Reason for changing the level of the guild's explicit content filter
|
||||
* @returns {Promise<Guild>}
|
||||
*/
|
||||
@@ -892,10 +895,9 @@ class Guild extends AnonymousGuild {
|
||||
return this.edit({ explicitContentFilter }, reason);
|
||||
}
|
||||
|
||||
/* eslint-disable max-len */
|
||||
/**
|
||||
* Edits the setting of the default message notifications of the guild.
|
||||
* @param {?(DefaultMessageNotificationLevel|number)} defaultMessageNotifications The new default message notification level of the guild
|
||||
* @param {?(GuildDefaultMessageNotificationLevel|number)} defaultMessageNotifications The new default message notification level of the guild
|
||||
* @param {string} [reason] Reason for changing the setting of the default message notifications
|
||||
* @returns {Promise<Guild>}
|
||||
*/
|
||||
@@ -931,7 +933,7 @@ class Guild extends AnonymousGuild {
|
||||
|
||||
/**
|
||||
* Edits the verification level of the guild.
|
||||
* @param {?VerificationLevel} verificationLevel The new verification level of the guild
|
||||
* @param {?GuildVerificationLevel} verificationLevel The new verification level of the guild
|
||||
* @param {string} [reason] Reason for changing the guild's verification level
|
||||
* @returns {Promise<Guild>}
|
||||
* @example
|
||||
|
||||
@@ -159,7 +159,7 @@ class Message extends Base {
|
||||
this.attachments = new Collection();
|
||||
if (data.attachments) {
|
||||
for (const attachment of data.attachments) {
|
||||
this.attachments.set(attachment.id, new Attachment(attachment.url, attachment.filename, attachment));
|
||||
this.attachments.set(attachment.id, new Attachment(attachment));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -644,7 +644,8 @@ class Message extends Base {
|
||||
* Only `MessageFlags.SuppressEmbeds` can be edited.
|
||||
* @property {Attachment[]} [attachments] An array of attachments to keep,
|
||||
* all attachments will be kept if omitted
|
||||
* @property {FileOptions[]|BufferResolvable[]|Attachment[]} [files] Files to add to the message
|
||||
* @property {Array<JSONEncodable<AttachmentPayload>>|BufferResolvable[]|Attachment[]|AttachmentBuilder[]} [files]
|
||||
* Files to add to the message
|
||||
* @property {ActionRow[]|ActionRowOptions[]} [components]
|
||||
* Action rows containing interactive components for the message (buttons, select menus)
|
||||
*/
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
const Interaction = require('./Interaction');
|
||||
const InteractionWebhook = require('./InteractionWebhook');
|
||||
const InteractionResponses = require('./interfaces/InteractionResponses');
|
||||
const { lazy } = require('../util/Util');
|
||||
|
||||
const getMessage = lazy(() => require('./Message').Message);
|
||||
|
||||
/**
|
||||
* Represents a message component interaction.
|
||||
@@ -21,9 +24,9 @@ class MessageComponentInteraction extends Interaction {
|
||||
|
||||
/**
|
||||
* The message to which the component was attached
|
||||
* @type {Message|APIMessage}
|
||||
* @type {Message}
|
||||
*/
|
||||
this.message = this.channel?.messages._add(data.message) ?? data.message;
|
||||
this.message = this.channel?.messages._add(data.message) ?? new (getMessage())(client, data.message);
|
||||
|
||||
/**
|
||||
* The custom id of the component which was interacted with
|
||||
|
||||
@@ -224,7 +224,8 @@ class MessagePayload {
|
||||
|
||||
/**
|
||||
* Resolves a single file into an object sendable to the API.
|
||||
* @param {BufferResolvable|Stream|FileOptions|Attachment} fileLike Something that could be resolved to a file
|
||||
* @param {BufferResolvable|Stream|JSONEncodable<AttachmentPayload>} fileLike Something that could
|
||||
* be resolved to a file
|
||||
* @returns {Promise<RawFile>}
|
||||
*/
|
||||
static async resolveFile(fileLike) {
|
||||
|
||||
@@ -52,6 +52,14 @@ class MessageReaction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the client user react with this reaction
|
||||
* @returns {Promise<MessageReaction>}
|
||||
*/
|
||||
react() {
|
||||
return this.message.react(this.emoji);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all users from this reaction.
|
||||
* @returns {Promise<MessageReaction>}
|
||||
|
||||
@@ -4,6 +4,9 @@ const Interaction = require('./Interaction');
|
||||
const InteractionWebhook = require('./InteractionWebhook');
|
||||
const ModalSubmitFields = require('./ModalSubmitFields');
|
||||
const InteractionResponses = require('./interfaces/InteractionResponses');
|
||||
const { lazy } = require('../util/Util');
|
||||
|
||||
const getMessage = lazy(() => require('./Message').Message);
|
||||
|
||||
/**
|
||||
* @typedef {Object} ModalData
|
||||
@@ -34,9 +37,9 @@ class ModalSubmitInteraction extends Interaction {
|
||||
if ('message' in data) {
|
||||
/**
|
||||
* The message associated with this interaction
|
||||
* @type {?(Message|APIMessage)}
|
||||
* @type {?Message}
|
||||
*/
|
||||
this.message = this.channel?.messages._add(data.message) ?? data.message;
|
||||
this.message = this.channel?.messages._add(data.message) ?? new (getMessage())(this.client, data.message);
|
||||
} else {
|
||||
this.message = null;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const { SelectMenuOptionBuilder: BuildersSelectMenuOption } = require('@discordjs/builders');
|
||||
const { SelectMenuOptionBuilder: BuildersSelectMenuOption, isJSONEncodable } = require('@discordjs/builders');
|
||||
const Transformers = require('../util/Transformers');
|
||||
const Util = require('../util/Util');
|
||||
|
||||
@@ -28,6 +28,18 @@ class SelectMenuOptionBuilder extends BuildersSelectMenuOption {
|
||||
}
|
||||
return super.setEmoji(emoji);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new select menu option builder from JSON data
|
||||
* @param {JSONEncodable<APISelectMenuOption>|APISelectMenuOption} other The other data
|
||||
* @returns {SelectMenuOptionBuilder}
|
||||
*/
|
||||
static from(other) {
|
||||
if (isJSONEncodable(other)) {
|
||||
return new this(other.toJSON());
|
||||
}
|
||||
return new this(other);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SelectMenuOptionBuilder;
|
||||
|
||||
@@ -70,10 +70,10 @@ class Sticker extends Base {
|
||||
|
||||
if ('tags' in sticker) {
|
||||
/**
|
||||
* An array of tags for the sticker
|
||||
* @type {?string[]}
|
||||
* Autocomplete/suggestions for the sticker
|
||||
* @type {?string}
|
||||
*/
|
||||
this.tags = sticker.tags.split(', ');
|
||||
this.tags = sticker.tags;
|
||||
} else {
|
||||
this.tags ??= null;
|
||||
}
|
||||
@@ -246,8 +246,7 @@ class Sticker extends Base {
|
||||
other.format === this.format &&
|
||||
other.name === this.name &&
|
||||
other.packId === this.packId &&
|
||||
other.tags.length === this.tags.length &&
|
||||
other.tags.every(tag => this.tags.includes(tag)) &&
|
||||
other.tags === this.tags &&
|
||||
other.available === this.available &&
|
||||
other.guildId === this.guildId &&
|
||||
other.sortValue === this.sortValue
|
||||
@@ -257,7 +256,7 @@ class Sticker extends Base {
|
||||
other.id === this.id &&
|
||||
other.description === this.description &&
|
||||
other.name === this.name &&
|
||||
other.tags === this.tags.join(', ')
|
||||
other.tags === this.tags
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ const MessageManager = require('../managers/MessageManager');
|
||||
/**
|
||||
* Represents a guild voice channel on Discord.
|
||||
* @extends {BaseGuildVoiceChannel}
|
||||
* @implements {TextBasedChannel}
|
||||
*/
|
||||
class VoiceChannel extends BaseGuildVoiceChannel {
|
||||
constructor(guild, data, client) {
|
||||
|
||||
@@ -6,6 +6,9 @@ const { Routes, WebhookType } = require('discord-api-types/v10');
|
||||
const MessagePayload = require('./MessagePayload');
|
||||
const { Error } = require('../errors');
|
||||
const DataResolver = require('../util/DataResolver');
|
||||
const { lazy } = require('../util/Util');
|
||||
|
||||
const getMessage = lazy(() => require('./Message').Message);
|
||||
|
||||
/**
|
||||
* Represents a webhook.
|
||||
@@ -132,7 +135,8 @@ class Webhook {
|
||||
* @typedef {Object} WebhookEditMessageOptions
|
||||
* @property {Embed[]|APIEmbed[]} [embeds] See {@link WebhookMessageOptions#embeds}
|
||||
* @property {string} [content] See {@link BaseMessageOptions#content}
|
||||
* @property {FileOptions[]|BufferResolvable[]|Attachment[]} [files] See {@link BaseMessageOptions#files}
|
||||
* @property {JSONEncodable<AttachmentPayload>|BufferResolvable[]|Attachment[]|AttachmentBuilder[]} [files]
|
||||
* See {@link BaseMessageOptions#files}
|
||||
* @property {MessageMentionOptions} [allowedMentions] See {@link BaseMessageOptions#allowedMentions}
|
||||
* @property {Attachment[]} [attachments] Attachments to send with the message
|
||||
* @property {ActionRow[]|ActionRowOptions[]} [components]
|
||||
@@ -144,7 +148,7 @@ class Webhook {
|
||||
/**
|
||||
* Sends a message with this webhook.
|
||||
* @param {string|MessagePayload|WebhookMessageOptions} options The options to provide
|
||||
* @returns {Promise<Message|APIMessage>}
|
||||
* @returns {Promise<Message>}
|
||||
* @example
|
||||
* // Send a basic message
|
||||
* webhook.send('hello!')
|
||||
@@ -207,7 +211,7 @@ class Webhook {
|
||||
|
||||
const { body, files } = await messagePayload.resolveFiles();
|
||||
const d = await this.client.rest.post(Routes.webhook(this.id, this.token), { body, files, query, auth: false });
|
||||
return this.client.channels?.cache.get(d.channel_id)?.messages._add(d, false) ?? d;
|
||||
return this.client.channels?.cache.get(d.channel_id)?.messages._add(d, false) ?? new (getMessage())(this.client, d);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -282,8 +286,7 @@ class Webhook {
|
||||
* Gets a message that was sent by this webhook.
|
||||
* @param {Snowflake|'@original'} message The id of the message to fetch
|
||||
* @param {WebhookFetchMessageOptions} [options={}] The options to provide to fetch the message.
|
||||
* @returns {Promise<Message|APIMessage>} Returns the raw message data if the webhook was instantiated as a
|
||||
* {@link WebhookClient} or if the channel is uncached, otherwise a {@link Message} will be returned
|
||||
* @returns {Promise<Message>} Returns the message sent by this webhook
|
||||
*/
|
||||
async fetchMessage(message, { cache = true, threadId } = {}) {
|
||||
if (!this.token) throw new Error('WEBHOOK_TOKEN_UNAVAILABLE');
|
||||
@@ -292,15 +295,17 @@ class Webhook {
|
||||
query: threadId ? makeURLSearchParams({ thread_id: threadId }) : undefined,
|
||||
auth: false,
|
||||
});
|
||||
return this.client.channels?.cache.get(data.channel_id)?.messages._add(data, cache) ?? data;
|
||||
return (
|
||||
this.client.channels?.cache.get(data.channel_id)?.messages._add(data, cache) ??
|
||||
new (getMessage())(this.client, data)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits a message that was sent by this webhook.
|
||||
* @param {MessageResolvable|'@original'} message The message to edit
|
||||
* @param {string|MessagePayload|WebhookEditMessageOptions} options The options to provide
|
||||
* @returns {Promise<Message|APIMessage>} Returns the raw message data if the webhook was instantiated as a
|
||||
* {@link WebhookClient} or if the channel is uncached, otherwise a {@link Message} will be returned
|
||||
* @returns {Promise<Message>} Returns the message edited by this webhook
|
||||
*/
|
||||
async editMessage(message, options) {
|
||||
if (!this.token) throw new Error('WEBHOOK_TOKEN_UNAVAILABLE');
|
||||
@@ -325,7 +330,7 @@ class Webhook {
|
||||
);
|
||||
|
||||
const messageManager = this.client.channels?.cache.get(d.channel_id)?.messages;
|
||||
if (!messageManager) return d;
|
||||
if (!messageManager) return new (getMessage())(this.client, d);
|
||||
|
||||
const existing = messageManager.cache.get(d.id);
|
||||
if (!existing) return messageManager._add(d);
|
||||
|
||||
@@ -103,21 +103,31 @@ class Collector extends EventEmitter {
|
||||
* @emits Collector#collect
|
||||
*/
|
||||
async handleCollect(...args) {
|
||||
const collect = await this.collect(...args);
|
||||
const collectedId = await this.collect(...args);
|
||||
|
||||
if (collect && (await this.filter(...args, this.collected))) {
|
||||
this.collected.set(collect, args[0]);
|
||||
if (collectedId) {
|
||||
const filterResult = await this.filter(...args, this.collected);
|
||||
if (filterResult) {
|
||||
this.collected.set(collectedId, args[0]);
|
||||
|
||||
/**
|
||||
* Emitted whenever an element is collected.
|
||||
* @event Collector#collect
|
||||
* @param {...*} args The arguments emitted by the listener
|
||||
*/
|
||||
this.emit('collect', ...args);
|
||||
/**
|
||||
* Emitted whenever an element is collected.
|
||||
* @event Collector#collect
|
||||
* @param {...*} args The arguments emitted by the listener
|
||||
*/
|
||||
this.emit('collect', ...args);
|
||||
|
||||
if (this._idletimeout) {
|
||||
clearTimeout(this._idletimeout);
|
||||
this._idletimeout = setTimeout(() => this.stop('idle'), this.options.idle).unref();
|
||||
if (this._idletimeout) {
|
||||
clearTimeout(this._idletimeout);
|
||||
this._idletimeout = setTimeout(() => this.stop('idle'), this.options.idle).unref();
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* Emitted whenever an element is not collected by the collector.
|
||||
* @event Collector#ignore
|
||||
* @param {...*} args The arguments emitted by the listener
|
||||
*/
|
||||
this.emit('ignore', ...args);
|
||||
}
|
||||
}
|
||||
this.checkEnd();
|
||||
|
||||
@@ -8,10 +8,10 @@ const InteractionResponse = require('../InteractionResponse');
|
||||
const MessagePayload = require('../MessagePayload');
|
||||
|
||||
/**
|
||||
* @typedef {Object} ModalData
|
||||
* @typedef {Object} ModalComponentData
|
||||
* @property {string} title The title of the modal
|
||||
* @property {string} customId The custom id of the modal
|
||||
* @property {ActionRowData[]} components The components within this modal
|
||||
* @property {ActionRow[]} components The components within this modal
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -64,7 +64,7 @@ class TextBasedChannel {
|
||||
* @property {FileOptions[]|BufferResolvable[]|Attachment[]} [files] Files to send with the message
|
||||
* @property {ActionRow[]|ActionRowOptions[]} [components]
|
||||
* Action rows containing interactive components for the message (buttons, select menus)
|
||||
* @property {Attachment[]} [attachments] Attachments to send in the message
|
||||
* @property {Array<JSONEncodable<AttachmentPayload>>} [attachments] Attachments to send in the message
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/**
|
||||
* @external ActivityFlags
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ActivityFlags}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external ActivityType
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ActivityType}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external APIActionRowComponent
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIActionRowComponent}
|
||||
@@ -13,21 +23,6 @@
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIApplicationCommand}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external ApplicationCommandType
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationCommandType}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external ApplicationCommandOptionType
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationCommandOptionType}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external ApplicationCommandPermissionType
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationCommandPermissionType}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external APIApplicationCommandOption
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIApplicationCommandOption}
|
||||
@@ -48,6 +43,11 @@
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIEmbed}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external APIEmbedField
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIEmbedField}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external APIEmoji
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIEmoji}
|
||||
@@ -88,11 +88,21 @@
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIMessageComponent}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external APIMessageComponentEmoji
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIMessageComponentEmoji}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external APIModalInteractionResponse
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIModalInteractionResponse}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external APIModalComponent
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIModalComponent}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external APIModalSubmission
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIModalSubmission}
|
||||
@@ -113,11 +123,36 @@
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APISelectMenuOption}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external APITextInputComponent
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APITextInputComponent}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external APIUser
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIUser}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external ApplicationCommandType
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationCommandType}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external ApplicationCommandOptionType
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationCommandOptionType}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external ApplicationCommandPermissionType
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationCommandPermissionType}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external ApplicationFlags
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationFlags}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external AuditLogEvent
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AuditLogEvent}
|
||||
@@ -238,6 +273,11 @@
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-rest/common/enum/Locale}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external LocaleString
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-rest/common#LocaleString}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external MessageActivityType
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/MessageActivityType}
|
||||
@@ -258,6 +298,16 @@
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/OAuth2Scopes}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external OverwriteType
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/OverwriteType}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external ChannelType
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ChannelType}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @external PermissionFlagsBits
|
||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-payloads/common#PermissionFlagsBits}
|
||||
|
||||
@@ -18,7 +18,7 @@ const { ComponentType } = require('discord-api-types/v10');
|
||||
* @property {ButtonStyle} style The style of the button
|
||||
* @property {?boolean} disabled Whether this button is disabled
|
||||
* @property {string} label The label of this button
|
||||
* @property {?APIComponentEmoji} emoji The emoji on this button
|
||||
* @property {?APIMessageComponentEmoji} emoji The emoji on this button
|
||||
* @property {?string} customId The custom id of the button
|
||||
* @property {?string} url The URL of the button
|
||||
*/
|
||||
@@ -28,7 +28,7 @@ const { ComponentType } = require('discord-api-types/v10');
|
||||
* @property {string} label The label of the option
|
||||
* @property {string} value The value of the option
|
||||
* @property {?string} description The description of the option
|
||||
* @property {?APIComponentEmoji} emoji The emoji on the option
|
||||
* @property {?APIMessageComponentEmoji} emoji The emoji on the option
|
||||
* @property {?boolean} default Whether this option is selected by default
|
||||
*/
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ const Transformers = require('./Transformers');
|
||||
* @property {number|number[]|string} [shards] The shard's id to run, or an array of shard ids. If not specified,
|
||||
* the client will spawn {@link ClientOptions#shardCount} shards. If set to `auto`, it will fetch the
|
||||
* recommended amount of shards from Discord and spawn that amount
|
||||
* @property {number} [closeTimeout=1] The amount of time in milliseconds to wait for the close frame to be received
|
||||
* from the WebSocket. Don't have this too high/low. Its best to have it between 2_000-6_000 ms.
|
||||
* @property {number} [shardCount=1] The total amount of shards used by all processes of this bot
|
||||
* (e.g. recommended shard count, shard count of the ShardingManager)
|
||||
* @property {CacheFactory} [makeCache] Function to create a cache.
|
||||
@@ -72,6 +74,7 @@ class Options extends null {
|
||||
*/
|
||||
static createDefault() {
|
||||
return {
|
||||
closeTimeout: 5_000,
|
||||
waitGuildTimeout: 15_000,
|
||||
shardCount: 1,
|
||||
makeCache: this.cacheWithLimits(this.DefaultMakeCacheSettings),
|
||||
|
||||
@@ -521,6 +521,16 @@ class Util extends null {
|
||||
static cleanCodeBlockContent(text) {
|
||||
return text.replaceAll('```', '`\u200b``');
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazily evaluates a callback function
|
||||
* @param {Function} cb The callback to lazily evaluate
|
||||
* @returns {Function}
|
||||
*/
|
||||
static lazy(cb) {
|
||||
let defaultValue;
|
||||
return () => (defaultValue ??= cb());
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Util;
|
||||
|
||||
206
packages/discord.js/typings/index.d.ts
vendored
206
packages/discord.js/typings/index.d.ts
vendored
@@ -29,6 +29,7 @@ import {
|
||||
ModalBuilder as BuildersModal,
|
||||
AnyComponentBuilder,
|
||||
ComponentBuilder,
|
||||
type RestOrArray,
|
||||
} from '@discordjs/builders';
|
||||
import { Collection } from '@discordjs/collection';
|
||||
import { BaseImageURLOptions, ImageURLOptions, RawFile, REST, RESTOptions } from '@discordjs/rest';
|
||||
@@ -117,6 +118,7 @@ import {
|
||||
LocalizationMap,
|
||||
LocaleString,
|
||||
MessageActivityType,
|
||||
APIAttachment,
|
||||
} from 'discord-api-types/v10';
|
||||
import { ChildProcess } from 'node:child_process';
|
||||
import { EventEmitter } from 'node:events';
|
||||
@@ -390,16 +392,19 @@ export interface InteractionResponseFields<Cached extends CacheType = CacheType>
|
||||
ephemeral: boolean | null;
|
||||
replied: boolean;
|
||||
webhook: InteractionWebhook;
|
||||
reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
|
||||
reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<Message>;
|
||||
reply(options: string | MessagePayload | InteractionReplyOptions): Promise<void>;
|
||||
deleteReply(): Promise<void>;
|
||||
editReply(options: string | MessagePayload | WebhookEditMessageOptions): Promise<GuildCacheMessage<Cached>>;
|
||||
deferReply(options: InteractionDeferReplyOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
|
||||
editReply(options: string | MessagePayload | WebhookEditMessageOptions): Promise<Message>;
|
||||
deferReply(options: InteractionDeferReplyOptions & { fetchReply: true }): Promise<Message>;
|
||||
deferReply(options?: InteractionDeferReplyOptions): Promise<void>;
|
||||
fetchReply(): Promise<GuildCacheMessage<Cached>>;
|
||||
followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<GuildCacheMessage<Cached>>;
|
||||
fetchReply(): Promise<Message>;
|
||||
followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<Message>;
|
||||
showModal(
|
||||
modal: JSONEncodable<APIModalInteractionResponseCallbackData> | ModalData | APIModalInteractionResponseCallbackData,
|
||||
modal:
|
||||
| JSONEncodable<APIModalInteractionResponseCallbackData>
|
||||
| ModalComponentData
|
||||
| APIModalInteractionResponseCallbackData,
|
||||
): Promise<void>;
|
||||
awaitModalSubmit(options: AwaitModalSubmitOptions<ModalSubmitInteraction>): Promise<ModalSubmitInteraction<Cached>>;
|
||||
}
|
||||
@@ -427,6 +432,7 @@ export abstract class CommandInteraction<Cached extends CacheType = CacheType> e
|
||||
public commandId: Snowflake;
|
||||
public commandName: string;
|
||||
public commandType: ApplicationCommandType;
|
||||
public commandGuildId: Snowflake | null;
|
||||
public deferred: boolean;
|
||||
public ephemeral: boolean | null;
|
||||
public replied: boolean;
|
||||
@@ -434,18 +440,23 @@ export abstract class CommandInteraction<Cached extends CacheType = CacheType> e
|
||||
public inGuild(): this is CommandInteraction<'raw' | 'cached'>;
|
||||
public inCachedGuild(): this is CommandInteraction<'cached'>;
|
||||
public inRawGuild(): this is CommandInteraction<'raw'>;
|
||||
public deferReply(options: InteractionDeferReplyOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
|
||||
public deferReply(
|
||||
options: InteractionDeferReplyOptions & { fetchReply: true },
|
||||
): Promise<Message<BooleanCache<Cached>>>;
|
||||
public deferReply(options?: InteractionDeferReplyOptions): Promise<InteractionResponse<BooleanCache<Cached>>>;
|
||||
public deleteReply(): Promise<void>;
|
||||
public editReply(options: string | MessagePayload | WebhookEditMessageOptions): Promise<GuildCacheMessage<Cached>>;
|
||||
public fetchReply(): Promise<GuildCacheMessage<Cached>>;
|
||||
public followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<GuildCacheMessage<Cached>>;
|
||||
public reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
|
||||
public editReply(options: string | MessagePayload | WebhookEditMessageOptions): Promise<Message>;
|
||||
public fetchReply(): Promise<Message>;
|
||||
public followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<Message>;
|
||||
public reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<Message<BooleanCache<Cached>>>;
|
||||
public reply(
|
||||
options: string | MessagePayload | InteractionReplyOptions,
|
||||
): Promise<InteractionResponse<BooleanCache<Cached>>>;
|
||||
public showModal(
|
||||
modal: JSONEncodable<APIModalInteractionResponseCallbackData> | ModalData | APIModalInteractionResponseCallbackData,
|
||||
modal:
|
||||
| JSONEncodable<APIModalInteractionResponseCallbackData>
|
||||
| ModalComponentData
|
||||
| APIModalInteractionResponseCallbackData,
|
||||
): Promise<void>;
|
||||
public awaitModalSubmit(
|
||||
options: AwaitModalSubmitOptions<ModalSubmitInteraction>,
|
||||
@@ -599,17 +610,18 @@ export class ButtonBuilder extends BuilderButtonComponent {
|
||||
export class SelectMenuBuilder extends BuilderSelectMenuComponent {
|
||||
public constructor(data?: Partial<SelectMenuComponentData | APISelectMenuComponent>);
|
||||
public override addOptions(
|
||||
options: (BuildersSelectMenuOption | SelectMenuComponentOptionData | APISelectMenuOption)[],
|
||||
...options: RestOrArray<BuildersSelectMenuOption | SelectMenuComponentOptionData | APISelectMenuOption>
|
||||
): this;
|
||||
public override setOptions(
|
||||
options: (BuildersSelectMenuOption | SelectMenuComponentOptionData | APISelectMenuOption)[],
|
||||
...options: RestOrArray<BuildersSelectMenuOption | SelectMenuComponentOptionData | APISelectMenuOption>
|
||||
): this;
|
||||
public static from(other: JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent): SelectMenuBuilder;
|
||||
}
|
||||
|
||||
export class SelectMenuOptionBuilder extends BuildersSelectMenuOption {
|
||||
public constructor(data?: SelectMenuComponentOptionData | APISelectMenuOption);
|
||||
public setEmoji(emoji: ComponentEmojiResolvable): this;
|
||||
public override setEmoji(emoji: ComponentEmojiResolvable): this;
|
||||
public static from(other: JSONEncodable<APISelectMenuOption> | APISelectMenuOption): SelectMenuOptionBuilder;
|
||||
}
|
||||
|
||||
export class ModalBuilder extends BuildersModal {
|
||||
@@ -738,15 +750,7 @@ export abstract class Channel extends Base {
|
||||
public get url(): string;
|
||||
public delete(): Promise<this>;
|
||||
public fetch(force?: boolean): Promise<this>;
|
||||
public isText(): this is TextChannel;
|
||||
public isDM(): this is DMChannel;
|
||||
public isVoice(): this is VoiceChannel;
|
||||
public isGroupDM(): this is PartialGroupDMChannel;
|
||||
public isCategory(): this is CategoryChannel;
|
||||
public isNews(): this is NewsChannel;
|
||||
public isThread(): this is ThreadChannel;
|
||||
public isStage(): this is StageChannel;
|
||||
public isDirectory(): this is DirectoryChannel;
|
||||
public isTextBased(): this is TextBasedChannel;
|
||||
public isDMBased(): this is PartialGroupDMChannel | DMChannel | PartialDMChannel;
|
||||
public isVoiceBased(): this is VoiceBasedChannel;
|
||||
@@ -872,6 +876,7 @@ export { Collection } from '@discordjs/collection';
|
||||
|
||||
export interface CollectorEventTypes<K, V, F extends unknown[] = []> {
|
||||
collect: [V, ...F];
|
||||
ignore: [V, ...F];
|
||||
dispose: [V, ...F];
|
||||
end: [collected: Collection<K, V>, reason: string];
|
||||
}
|
||||
@@ -1112,6 +1117,7 @@ export class Guild extends AnonymousGuild {
|
||||
options?: GuildAuditLogsFetchOptions<T>,
|
||||
): Promise<GuildAuditLogs<T>>;
|
||||
public fetchIntegrations(): Promise<Collection<Snowflake | string, Integration>>;
|
||||
public fetchMe(options?: BaseFetchOptions): Promise<GuildMember>;
|
||||
public fetchOwner(options?: BaseFetchOptions): Promise<GuildMember>;
|
||||
public fetchPreview(): Promise<GuildPreview>;
|
||||
public fetchTemplates(): Promise<Collection<GuildTemplate['code'], GuildTemplate>>;
|
||||
@@ -1520,11 +1526,11 @@ export class InteractionCollector<T extends Interaction> extends Collector<Snowf
|
||||
public collect(interaction: Interaction): Snowflake;
|
||||
public empty(): void;
|
||||
public dispose(interaction: Interaction): Snowflake;
|
||||
public on(event: 'collect' | 'dispose', listener: (interaction: T) => Awaitable<void>): this;
|
||||
public on(event: 'collect' | 'dispose' | 'ignore', listener: (interaction: T) => Awaitable<void>): this;
|
||||
public on(event: 'end', listener: (collected: Collection<Snowflake, T>, reason: string) => Awaitable<void>): this;
|
||||
public on(event: string, listener: (...args: any[]) => Awaitable<void>): this;
|
||||
|
||||
public once(event: 'collect' | 'dispose', listener: (interaction: T) => Awaitable<void>): this;
|
||||
public once(event: 'collect' | 'dispose' | 'ignore', listener: (interaction: T) => Awaitable<void>): this;
|
||||
public once(event: 'end', listener: (collected: Collection<Snowflake, T>, reason: string) => Awaitable<void>): this;
|
||||
public once(event: string, listener: (...args: any[]) => Awaitable<void>): this;
|
||||
}
|
||||
@@ -1532,7 +1538,7 @@ export class InteractionCollector<T extends Interaction> extends Collector<Snowf
|
||||
export class InteractionWebhook extends PartialWebhookMixin() {
|
||||
public constructor(client: Client, id: Snowflake, token: string);
|
||||
public token: string;
|
||||
public send(options: string | MessagePayload | InteractionReplyOptions): Promise<Message | APIMessage>;
|
||||
public send(options: string | MessagePayload | InteractionReplyOptions): Promise<Message>;
|
||||
}
|
||||
|
||||
export class Invite extends Base {
|
||||
@@ -1696,9 +1702,22 @@ export class Message<Cached extends boolean = boolean> extends Base {
|
||||
public inGuild(): this is Message<true> & this;
|
||||
}
|
||||
|
||||
export class Attachment {
|
||||
public constructor(attachment: BufferResolvable | Stream, name?: string, data?: RawAttachmentData);
|
||||
export class AttachmentBuilder {
|
||||
public constructor(attachment: BufferResolvable | Stream, data?: AttachmentData);
|
||||
public attachment: BufferResolvable | Stream;
|
||||
public description: string | null;
|
||||
public name: string | null;
|
||||
public get spoiler(): boolean;
|
||||
public setDescription(description: string): this;
|
||||
public setFile(attachment: BufferResolvable | Stream, name?: string): this;
|
||||
public setName(name: string): this;
|
||||
public setSpoiler(spoiler?: boolean): this;
|
||||
public toJSON(): unknown;
|
||||
public static from(other: JSONEncodable<AttachmentPayload>): AttachmentBuilder;
|
||||
}
|
||||
|
||||
export class Attachment {
|
||||
private constructor(data: APIAttachment);
|
||||
public attachment: BufferResolvable | Stream;
|
||||
public contentType: string | null;
|
||||
public description: string | null;
|
||||
@@ -1711,10 +1730,6 @@ export class Attachment {
|
||||
public get spoiler(): boolean;
|
||||
public url: string;
|
||||
public width: number | null;
|
||||
public setDescription(description: string): this;
|
||||
public setFile(attachment: BufferResolvable | Stream, name?: string): this;
|
||||
public setName(name: string): this;
|
||||
public setSpoiler(spoiler?: boolean): this;
|
||||
public toJSON(): unknown;
|
||||
}
|
||||
|
||||
@@ -1745,30 +1760,37 @@ export class MessageComponentInteraction<Cached extends CacheType = CacheType> e
|
||||
public channelId: Snowflake;
|
||||
public deferred: boolean;
|
||||
public ephemeral: boolean | null;
|
||||
public message: GuildCacheMessage<Cached>;
|
||||
public message: Message<BooleanCache<Cached>>;
|
||||
public replied: boolean;
|
||||
public webhook: InteractionWebhook;
|
||||
public inGuild(): this is MessageComponentInteraction<'raw' | 'cached'>;
|
||||
public inCachedGuild(): this is MessageComponentInteraction<'cached'>;
|
||||
public inRawGuild(): this is MessageComponentInteraction<'raw'>;
|
||||
public deferReply(options: InteractionDeferReplyOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
|
||||
public deferReply(
|
||||
options: InteractionDeferReplyOptions & { fetchReply: true },
|
||||
): Promise<Message<BooleanCache<Cached>>>;
|
||||
public deferReply(options?: InteractionDeferReplyOptions): Promise<InteractionResponse<BooleanCache<Cached>>>;
|
||||
public deferUpdate(options: InteractionDeferUpdateOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
|
||||
public deferUpdate(
|
||||
options: InteractionDeferUpdateOptions & { fetchReply: true },
|
||||
): Promise<Message<BooleanCache<Cached>>>;
|
||||
public deferUpdate(options?: InteractionDeferUpdateOptions): Promise<InteractionResponse<BooleanCache<Cached>>>;
|
||||
public deleteReply(): Promise<void>;
|
||||
public editReply(options: string | MessagePayload | WebhookEditMessageOptions): Promise<GuildCacheMessage<Cached>>;
|
||||
public fetchReply(): Promise<GuildCacheMessage<Cached>>;
|
||||
public followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<GuildCacheMessage<Cached>>;
|
||||
public reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
|
||||
public editReply(options: string | MessagePayload | WebhookEditMessageOptions): Promise<Message>;
|
||||
public fetchReply(): Promise<Message>;
|
||||
public followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<Message>;
|
||||
public reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<Message<BooleanCache<Cached>>>;
|
||||
public reply(
|
||||
options: string | MessagePayload | InteractionReplyOptions,
|
||||
): Promise<InteractionResponse<BooleanCache<Cached>>>;
|
||||
public update(options: InteractionUpdateOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
|
||||
public update(options: InteractionUpdateOptions & { fetchReply: true }): Promise<Message>;
|
||||
public update(
|
||||
options: string | MessagePayload | InteractionUpdateOptions,
|
||||
): Promise<InteractionResponse<BooleanCache<Cached>>>;
|
||||
public showModal(
|
||||
modal: JSONEncodable<APIModalInteractionResponseCallbackData> | ModalData | APIModalInteractionResponseCallbackData,
|
||||
modal:
|
||||
| JSONEncodable<APIModalInteractionResponseCallbackData>
|
||||
| ModalComponentData
|
||||
| APIModalInteractionResponseCallbackData,
|
||||
): Promise<void>;
|
||||
public awaitModalSubmit(
|
||||
options: AwaitModalSubmitOptions<ModalSubmitInteraction>,
|
||||
@@ -1838,7 +1860,9 @@ export class MessagePayload {
|
||||
options: string | MessageOptions | WebhookMessageOptions,
|
||||
extra?: MessageOptions | WebhookMessageOptions,
|
||||
): MessagePayload;
|
||||
public static resolveFile(fileLike: BufferResolvable | Stream | FileOptions | Attachment): Promise<RawFile>;
|
||||
public static resolveFile(
|
||||
fileLike: BufferResolvable | Stream | AttachmentPayload | JSONEncodable<AttachmentPayload>,
|
||||
): Promise<RawFile>;
|
||||
|
||||
public makeContent(): string | undefined;
|
||||
public resolveBody(): this;
|
||||
@@ -1856,11 +1880,18 @@ export class MessageReaction {
|
||||
public message: Message | PartialMessage;
|
||||
public get partial(): false;
|
||||
public users: ReactionUserManager;
|
||||
public react(): Promise<MessageReaction>;
|
||||
public remove(): Promise<MessageReaction>;
|
||||
public fetch(): Promise<MessageReaction>;
|
||||
public toJSON(): unknown;
|
||||
}
|
||||
|
||||
export interface ModalComponentData {
|
||||
customId: string;
|
||||
title: string;
|
||||
components: (ActionRow<ModalActionRowComponent> | ActionRowData<ModalActionRowComponentData>)[];
|
||||
}
|
||||
|
||||
export interface BaseModalData {
|
||||
customId: string;
|
||||
type: ComponentType;
|
||||
@@ -1889,12 +1920,12 @@ export class ModalSubmitFields {
|
||||
|
||||
export interface ModalMessageModalSubmitInteraction<Cached extends CacheType = CacheType>
|
||||
extends ModalSubmitInteraction<Cached> {
|
||||
message: GuildCacheMessage<Cached>;
|
||||
update(options: InteractionUpdateOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
|
||||
message: Message<BooleanCache<Cached>>;
|
||||
update(options: InteractionUpdateOptions & { fetchReply: true }): Promise<Message>;
|
||||
update(
|
||||
options: string | MessagePayload | InteractionUpdateOptions,
|
||||
): Promise<InteractionResponse<BooleanCache<Cached>>>;
|
||||
deferUpdate(options: InteractionDeferUpdateOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
|
||||
deferUpdate(options: InteractionDeferUpdateOptions & { fetchReply: true }): Promise<Message>;
|
||||
deferUpdate(options?: InteractionDeferUpdateOptions): Promise<InteractionResponse<BooleanCache<Cached>>>;
|
||||
inGuild(): this is ModalMessageModalSubmitInteraction<'raw' | 'cached'>;
|
||||
inCachedGuild(): this is ModalMessageModalSubmitInteraction<'cached'>;
|
||||
@@ -1908,19 +1939,23 @@ export class ModalSubmitInteraction<Cached extends CacheType = CacheType> extend
|
||||
public readonly fields: ModalSubmitFields;
|
||||
public deferred: boolean;
|
||||
public ephemeral: boolean | null;
|
||||
public message: GuildCacheMessage<Cached> | null;
|
||||
public message: Message<BooleanCache<Cached>> | null;
|
||||
public replied: boolean;
|
||||
public readonly webhook: InteractionWebhook;
|
||||
public reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
|
||||
public reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<Message>;
|
||||
public reply(
|
||||
options: string | MessagePayload | InteractionReplyOptions,
|
||||
): Promise<InteractionResponse<BooleanCache<Cached>>>;
|
||||
public deleteReply(): Promise<void>;
|
||||
public editReply(options: string | MessagePayload | WebhookEditMessageOptions): Promise<GuildCacheMessage<Cached>>;
|
||||
public deferReply(options: InteractionDeferReplyOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
|
||||
public editReply(
|
||||
options: string | MessagePayload | WebhookEditMessageOptions,
|
||||
): Promise<Message<BooleanCache<Cached>>>;
|
||||
public deferReply(
|
||||
options: InteractionDeferReplyOptions & { fetchReply: true },
|
||||
): Promise<Message<BooleanCache<Cached>>>;
|
||||
public deferReply(options?: InteractionDeferReplyOptions): Promise<InteractionResponse<BooleanCache<Cached>>>;
|
||||
public fetchReply(): Promise<GuildCacheMessage<Cached>>;
|
||||
public followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<GuildCacheMessage<Cached>>;
|
||||
public fetchReply(): Promise<Message<BooleanCache<Cached>>>;
|
||||
public followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<Message<BooleanCache<Cached>>>;
|
||||
public inGuild(): this is ModalSubmitInteraction<'raw' | 'cached'>;
|
||||
public inCachedGuild(): this is ModalSubmitInteraction<'cached'>;
|
||||
public inRawGuild(): this is ModalSubmitInteraction<'raw'>;
|
||||
@@ -2011,11 +2046,17 @@ export class ReactionCollector extends Collector<Snowflake | string, MessageReac
|
||||
public dispose(reaction: MessageReaction, user: User): Snowflake | string | null;
|
||||
public empty(): void;
|
||||
|
||||
public on(event: 'collect' | 'dispose' | 'remove', listener: (reaction: MessageReaction, user: User) => void): this;
|
||||
public on(
|
||||
event: 'collect' | 'dispose' | 'remove' | 'ignore',
|
||||
listener: (reaction: MessageReaction, user: User) => void,
|
||||
): this;
|
||||
public on(event: 'end', listener: (collected: Collection<Snowflake, MessageReaction>, reason: string) => void): this;
|
||||
public on(event: string, listener: (...args: any[]) => void): this;
|
||||
|
||||
public once(event: 'collect' | 'dispose' | 'remove', listener: (reaction: MessageReaction, user: User) => void): this;
|
||||
public once(
|
||||
event: 'collect' | 'dispose' | 'remove' | 'ignore',
|
||||
listener: (reaction: MessageReaction, user: User) => void,
|
||||
): this;
|
||||
public once(
|
||||
event: 'end',
|
||||
listener: (collected: Collection<Snowflake, MessageReaction>, reason: string) => void,
|
||||
@@ -2264,7 +2305,7 @@ export class Sticker extends Base {
|
||||
public packId: Snowflake | null;
|
||||
public get partial(): boolean;
|
||||
public sortValue: number | null;
|
||||
public tags: string[] | null;
|
||||
public tags: string | null;
|
||||
public type: StickerType | null;
|
||||
public user: User | null;
|
||||
public get url(): string;
|
||||
@@ -2719,9 +2760,9 @@ export class WebhookClient extends WebhookMixin(BaseClient) {
|
||||
public editMessage(
|
||||
message: MessageResolvable,
|
||||
options: string | MessagePayload | WebhookEditMessageOptions,
|
||||
): Promise<APIMessage>;
|
||||
public fetchMessage(message: Snowflake, options?: WebhookFetchMessageOptions): Promise<APIMessage>;
|
||||
public send(options: string | MessagePayload | WebhookMessageOptions): Promise<APIMessage>;
|
||||
): Promise<Message>;
|
||||
public fetchMessage(message: Snowflake, options?: WebhookFetchMessageOptions): Promise<Message>;
|
||||
public send(options: string | MessagePayload | WebhookMessageOptions): Promise<Message>;
|
||||
}
|
||||
|
||||
export class WebSocketManager extends EventEmitter {
|
||||
@@ -2779,6 +2820,8 @@ export class WebSocketShard extends EventEmitter {
|
||||
private eventsAttached: boolean;
|
||||
private expectedGuilds: Set<Snowflake> | null;
|
||||
private readyTimeout: NodeJS.Timeout | null;
|
||||
private closeEmitted: boolean;
|
||||
private wsCloseTimeout: NodeJS.Timeout | null;
|
||||
|
||||
public manager: WebSocketManager;
|
||||
public id: number;
|
||||
@@ -2794,6 +2837,7 @@ export class WebSocketShard extends EventEmitter {
|
||||
private onPacket(packet: unknown): void;
|
||||
private checkReady(): void;
|
||||
private setHelloTimeout(time?: number): void;
|
||||
private setWsCloseTimeout(time?: number): void;
|
||||
private setHeartbeatTimer(time: number): void;
|
||||
private sendHeartbeat(): void;
|
||||
private ackHeartbeat(): void;
|
||||
@@ -2803,6 +2847,7 @@ export class WebSocketShard extends EventEmitter {
|
||||
private _send(data: unknown): void;
|
||||
private processQueue(): void;
|
||||
private destroy(destroyOptions?: { closeCode?: number; reset?: boolean; emit?: boolean; log?: boolean }): void;
|
||||
private emitClose(event?: CloseEvent): void;
|
||||
private _cleanupConnection(): void;
|
||||
private _emitDestroyed(): void;
|
||||
|
||||
@@ -3199,7 +3244,7 @@ export class GuildStickerManager extends CachedManager<Snowflake, Sticker, Stick
|
||||
private constructor(guild: Guild, iterable?: Iterable<RawStickerData>);
|
||||
public guild: Guild;
|
||||
public create(
|
||||
file: BufferResolvable | Stream | FileOptions | Attachment,
|
||||
file: BufferResolvable | Stream | AttachmentPayload | JSONEncodable<AttachmentBuilder>,
|
||||
name: string,
|
||||
tags: string,
|
||||
options?: GuildStickerCreateOptions,
|
||||
@@ -3336,6 +3381,7 @@ export class ThreadMemberManager extends CachedManager<Snowflake, ThreadMember,
|
||||
public add(member: UserResolvable | '@me', reason?: string): Promise<Snowflake>;
|
||||
public fetch(options?: ThreadMemberFetchOptions): Promise<ThreadMember>;
|
||||
public fetch(cache?: boolean): Promise<Collection<Snowflake, ThreadMember>>;
|
||||
public fetchMe(options?: BaseFetchOptions): Promise<ThreadMember>;
|
||||
public remove(id: Snowflake | '@me', reason?: string): Promise<Snowflake>;
|
||||
}
|
||||
|
||||
@@ -3406,9 +3452,9 @@ export interface PartialWebhookFields {
|
||||
editMessage(
|
||||
message: MessageResolvable | '@original',
|
||||
options: string | MessagePayload | WebhookEditMessageOptions,
|
||||
): Promise<Message | APIMessage>;
|
||||
fetchMessage(message: Snowflake | '@original', options?: WebhookFetchMessageOptions): Promise<Message | APIMessage>;
|
||||
send(options: string | MessagePayload | Omit<WebhookMessageOptions, 'flags'>): Promise<Message | APIMessage>;
|
||||
): Promise<Message>;
|
||||
fetchMessage(message: Snowflake | '@original', options?: WebhookFetchMessageOptions): Promise<Message>;
|
||||
send(options: string | MessagePayload | Omit<WebhookMessageOptions, 'flags'>): Promise<Message>;
|
||||
}
|
||||
|
||||
export interface WebhookFields extends PartialWebhookFields {
|
||||
@@ -3454,6 +3500,11 @@ export interface BaseApplicationCommandData {
|
||||
defaultPermission?: boolean;
|
||||
}
|
||||
|
||||
export interface AttachmentData {
|
||||
name?: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export type CommandOptionDataTypeResolvable = ApplicationCommandOptionType;
|
||||
|
||||
export type CommandOptionChannelResolvableType = ApplicationCommandOptionType.Channel;
|
||||
@@ -3751,7 +3802,7 @@ export interface ChannelData {
|
||||
name?: string;
|
||||
type?: Pick<typeof ChannelType, 'GuildText' | 'GuildNews'>;
|
||||
position?: number;
|
||||
topic?: string;
|
||||
topic?: string | null;
|
||||
nsfw?: boolean;
|
||||
bitrate?: number;
|
||||
userLimit?: number;
|
||||
@@ -3874,6 +3925,7 @@ export interface ClientFetchInviteOptions {
|
||||
export interface ClientOptions {
|
||||
shards?: number | number[] | 'auto';
|
||||
shardCount?: number;
|
||||
closeTimeout?: number;
|
||||
makeCache?: CacheFactory;
|
||||
allowedMentions?: MessageMentionOptions;
|
||||
partials?: Partials[];
|
||||
@@ -3940,7 +3992,7 @@ export interface CommandInteractionOption<Cached extends CacheType = CacheType>
|
||||
channel?: CacheTypeReducer<Cached, GuildBasedChannel, APIInteractionDataResolvedChannel>;
|
||||
role?: CacheTypeReducer<Cached, Role, APIRole>;
|
||||
attachment?: Attachment;
|
||||
message?: GuildCacheMessage<Cached>;
|
||||
message?: Message<BooleanCache<Cached>>;
|
||||
}
|
||||
|
||||
export interface CommandInteractionResolvedData<Cached extends CacheType = CacheType> {
|
||||
@@ -4241,7 +4293,7 @@ export interface FetchThreadsOptions {
|
||||
active?: boolean;
|
||||
}
|
||||
|
||||
export interface FileOptions {
|
||||
export interface AttachmentPayload {
|
||||
attachment: BufferResolvable | Stream;
|
||||
name?: string;
|
||||
description?: string;
|
||||
@@ -4368,7 +4420,7 @@ export type GuildBanResolvable = GuildBan | UserResolvable;
|
||||
export type GuildChannelResolvable = Snowflake | GuildBasedChannel;
|
||||
|
||||
export interface GuildChannelCreateOptions extends Omit<CategoryCreateChannelOptions, 'type'> {
|
||||
parent?: CategoryChannelResolvable;
|
||||
parent?: CategoryChannelResolvable | null;
|
||||
type?: Exclude<
|
||||
ChannelType,
|
||||
| ChannelType.DM
|
||||
@@ -4672,10 +4724,17 @@ export type MessageChannelComponentCollectorOptions<T extends MessageComponentIn
|
||||
>;
|
||||
|
||||
export interface MessageEditOptions {
|
||||
attachments?: Attachment[];
|
||||
attachments?: JSONEncodable<AttachmentPayload>[];
|
||||
content?: string | null;
|
||||
embeds?: (JSONEncodable<APIEmbed> | APIEmbed)[] | null;
|
||||
files?: (FileOptions | BufferResolvable | Stream | Attachment)[];
|
||||
files?: (
|
||||
| BufferResolvable
|
||||
| Stream
|
||||
| JSONEncodable<APIAttachment>
|
||||
| Attachment
|
||||
| AttachmentBuilder
|
||||
| AttachmentPayload
|
||||
)[];
|
||||
flags?: BitFieldResolvable<MessageFlagsString, number>;
|
||||
allowedMentions?: MessageMentionOptions;
|
||||
components?: (
|
||||
@@ -4726,10 +4785,17 @@ export interface MessageOptions {
|
||||
| APIActionRowComponent<APIMessageActionRowComponent>
|
||||
)[];
|
||||
allowedMentions?: MessageMentionOptions;
|
||||
files?: (FileOptions | BufferResolvable | Stream | Attachment)[];
|
||||
files?: (
|
||||
| BufferResolvable
|
||||
| Stream
|
||||
| JSONEncodable<APIAttachment>
|
||||
| Attachment
|
||||
| AttachmentBuilder
|
||||
| AttachmentPayload
|
||||
)[];
|
||||
reply?: ReplyOptions;
|
||||
stickers?: StickerResolvable[];
|
||||
attachments?: Attachment[];
|
||||
attachments?: JSONEncodable<AttachmentPayload>[];
|
||||
flags?: BitFieldResolvable<Extract<MessageFlagsString, 'SuppressEmbeds'>, number>;
|
||||
}
|
||||
|
||||
@@ -4858,7 +4924,7 @@ export interface PartialChannelData {
|
||||
| ChannelType.GuildStageVoice
|
||||
>;
|
||||
name: string;
|
||||
topic?: string;
|
||||
topic?: string | null;
|
||||
nsfw?: boolean;
|
||||
bitrate?: number;
|
||||
userLimit?: number;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { ChildProcess } from 'child_process';
|
||||
import {
|
||||
APIInteractionGuildMember,
|
||||
APIMessage,
|
||||
APIPartialChannel,
|
||||
APIPartialGuild,
|
||||
APIInteractionDataResolvedGuildMember,
|
||||
@@ -57,7 +56,7 @@ import {
|
||||
Interaction,
|
||||
InteractionCollector,
|
||||
Message,
|
||||
Attachment,
|
||||
AttachmentBuilder,
|
||||
MessageCollector,
|
||||
MessageComponentInteraction,
|
||||
MessageReaction,
|
||||
@@ -123,6 +122,7 @@ import {
|
||||
ChannelMention,
|
||||
UserMention,
|
||||
PartialGroupDMChannel,
|
||||
Attachment,
|
||||
} from '.';
|
||||
import { expectAssignable, expectDeprecated, expectNotAssignable, expectNotType, expectType } from 'tsd';
|
||||
import { UnsafeButtonBuilder, UnsafeEmbedBuilder, UnsafeSelectMenuBuilder } from '@discordjs/builders';
|
||||
@@ -529,7 +529,7 @@ client.on('guildCreate', async g => {
|
||||
const channel = g.channels.cache.random();
|
||||
if (!channel) return;
|
||||
|
||||
if (channel.isText()) {
|
||||
if (channel.type === ChannelType.GuildText) {
|
||||
const row: ActionRowData<MessageActionRowComponentData> = {
|
||||
type: ComponentType.ActionRow,
|
||||
components: [
|
||||
@@ -615,7 +615,7 @@ client.on('messageCreate', async message => {
|
||||
assertIsMessage(channel.send({}));
|
||||
assertIsMessage(channel.send({ embeds: [] }));
|
||||
|
||||
const attachment = new Attachment('file.png');
|
||||
const attachment = new AttachmentBuilder('file.png');
|
||||
const embed = new EmbedBuilder();
|
||||
assertIsMessage(channel.send({ files: [attachment] }));
|
||||
assertIsMessage(channel.send({ embeds: [embed] }));
|
||||
@@ -1186,20 +1186,20 @@ client.on('interactionCreate', async interaction => {
|
||||
}
|
||||
|
||||
if (interaction.isMessageContextMenuCommand()) {
|
||||
expectType<Message | APIMessage>(interaction.targetMessage);
|
||||
expectType<Message>(interaction.targetMessage);
|
||||
if (interaction.inCachedGuild()) {
|
||||
expectType<Message<true>>(interaction.targetMessage);
|
||||
} else if (interaction.inRawGuild()) {
|
||||
expectType<APIMessage>(interaction.targetMessage);
|
||||
expectType<Message<false>>(interaction.targetMessage);
|
||||
} else if (interaction.inGuild()) {
|
||||
expectType<Message | APIMessage>(interaction.targetMessage);
|
||||
expectType<Message>(interaction.targetMessage);
|
||||
}
|
||||
}
|
||||
|
||||
if (interaction.isButton()) {
|
||||
expectType<ButtonInteraction>(interaction);
|
||||
expectType<ButtonComponent | APIButtonComponent>(interaction.component);
|
||||
expectType<Message | APIMessage>(interaction.message);
|
||||
expectType<Message>(interaction.message);
|
||||
if (interaction.inCachedGuild()) {
|
||||
expectAssignable<ButtonInteraction>(interaction);
|
||||
expectType<ButtonComponent>(interaction.component);
|
||||
@@ -1209,22 +1209,22 @@ client.on('interactionCreate', async interaction => {
|
||||
} else if (interaction.inRawGuild()) {
|
||||
expectAssignable<ButtonInteraction>(interaction);
|
||||
expectType<APIButtonComponent>(interaction.component);
|
||||
expectType<APIMessage>(interaction.message);
|
||||
expectType<Message<false>>(interaction.message);
|
||||
expectType<null>(interaction.guild);
|
||||
expectType<Promise<APIMessage>>(interaction.reply({ fetchReply: true }));
|
||||
expectType<Promise<Message<false>>>(interaction.reply({ fetchReply: true }));
|
||||
} else if (interaction.inGuild()) {
|
||||
expectAssignable<ButtonInteraction>(interaction);
|
||||
expectType<ButtonComponent | APIButtonComponent>(interaction.component);
|
||||
expectType<Message | APIMessage>(interaction.message);
|
||||
expectType<Message>(interaction.message);
|
||||
expectAssignable<Guild | null>(interaction.guild);
|
||||
expectType<Promise<APIMessage | Message>>(interaction.reply({ fetchReply: true }));
|
||||
expectType<Promise<Message>>(interaction.reply({ fetchReply: true }));
|
||||
}
|
||||
}
|
||||
|
||||
if (interaction.isMessageComponent()) {
|
||||
expectType<MessageComponentInteraction>(interaction);
|
||||
expectType<MessageActionRowComponent | APIButtonComponent | APISelectMenuComponent>(interaction.component);
|
||||
expectType<Message | APIMessage>(interaction.message);
|
||||
expectType<Message>(interaction.message);
|
||||
if (interaction.inCachedGuild()) {
|
||||
expectAssignable<MessageComponentInteraction>(interaction);
|
||||
expectType<MessageActionRowComponent>(interaction.component);
|
||||
@@ -1234,22 +1234,22 @@ client.on('interactionCreate', async interaction => {
|
||||
} else if (interaction.inRawGuild()) {
|
||||
expectAssignable<MessageComponentInteraction>(interaction);
|
||||
expectType<APIButtonComponent | APISelectMenuComponent>(interaction.component);
|
||||
expectType<APIMessage>(interaction.message);
|
||||
expectType<Message<false>>(interaction.message);
|
||||
expectType<null>(interaction.guild);
|
||||
expectType<Promise<APIMessage>>(interaction.reply({ fetchReply: true }));
|
||||
expectType<Promise<Message<false>>>(interaction.reply({ fetchReply: true }));
|
||||
} else if (interaction.inGuild()) {
|
||||
expectAssignable<MessageComponentInteraction>(interaction);
|
||||
expectType<MessageActionRowComponent | APIButtonComponent | APISelectMenuComponent>(interaction.component);
|
||||
expectType<Message | APIMessage>(interaction.message);
|
||||
expectType<Message>(interaction.message);
|
||||
expectType<Guild | null>(interaction.guild);
|
||||
expectType<Promise<APIMessage | Message>>(interaction.reply({ fetchReply: true }));
|
||||
expectType<Promise<Message>>(interaction.reply({ fetchReply: true }));
|
||||
}
|
||||
}
|
||||
|
||||
if (interaction.isSelectMenu()) {
|
||||
expectType<SelectMenuInteraction>(interaction);
|
||||
expectType<SelectMenuComponent | APISelectMenuComponent>(interaction.component);
|
||||
expectType<Message | APIMessage>(interaction.message);
|
||||
expectType<Message>(interaction.message);
|
||||
if (interaction.inCachedGuild()) {
|
||||
expectAssignable<SelectMenuInteraction>(interaction);
|
||||
expectType<SelectMenuComponent>(interaction.component);
|
||||
@@ -1259,15 +1259,15 @@ client.on('interactionCreate', async interaction => {
|
||||
} else if (interaction.inRawGuild()) {
|
||||
expectAssignable<SelectMenuInteraction>(interaction);
|
||||
expectType<APISelectMenuComponent>(interaction.component);
|
||||
expectType<APIMessage>(interaction.message);
|
||||
expectType<Message<false>>(interaction.message);
|
||||
expectType<null>(interaction.guild);
|
||||
expectType<Promise<APIMessage>>(interaction.reply({ fetchReply: true }));
|
||||
expectType<Promise<Message<false>>>(interaction.reply({ fetchReply: true }));
|
||||
} else if (interaction.inGuild()) {
|
||||
expectAssignable<SelectMenuInteraction>(interaction);
|
||||
expectType<SelectMenuComponent | APISelectMenuComponent>(interaction.component);
|
||||
expectType<Message | APIMessage>(interaction.message);
|
||||
expectType<Message>(interaction.message);
|
||||
expectType<Guild | null>(interaction.guild);
|
||||
expectType<Promise<Message | APIMessage>>(interaction.reply({ fetchReply: true }));
|
||||
expectType<Promise<Message>>(interaction.reply({ fetchReply: true }));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1275,7 +1275,7 @@ client.on('interactionCreate', async interaction => {
|
||||
if (interaction.inRawGuild()) {
|
||||
expectNotAssignable<Interaction<'cached'>>(interaction);
|
||||
expectAssignable<ChatInputCommandInteraction>(interaction);
|
||||
expectType<Promise<APIMessage>>(interaction.reply({ fetchReply: true }));
|
||||
expectType<Promise<Message<false>>>(interaction.reply({ fetchReply: true }));
|
||||
expectType<APIInteractionDataResolvedGuildMember | null>(interaction.options.getMember('test'));
|
||||
|
||||
expectType<APIInteractionDataResolvedChannel>(interaction.options.getChannel('test', true));
|
||||
@@ -1297,7 +1297,7 @@ client.on('interactionCreate', async interaction => {
|
||||
// @ts-expect-error
|
||||
consumeCachedCommand(interaction);
|
||||
expectType<ChatInputCommandInteraction>(interaction);
|
||||
expectType<Promise<Message | APIMessage>>(interaction.reply({ fetchReply: true }));
|
||||
expectType<Promise<Message>>(interaction.reply({ fetchReply: true }));
|
||||
expectType<APIInteractionDataResolvedGuildMember | GuildMember | null>(interaction.options.getMember('test'));
|
||||
|
||||
expectType<GuildBasedChannel | APIInteractionDataResolvedChannel>(interaction.options.getChannel('test', true));
|
||||
|
||||
@@ -30,9 +30,13 @@ pnpm add @discordjs/proxy
|
||||
|
||||
- [Website](https://discord.js.org/) ([source](https://github.com/discordjs/website))
|
||||
- [Documentation](https://discord.js.org/#/docs/proxy)
|
||||
- [Guide](https://discordjs.guide/) ([source](https://github.com/discordjs/guide))
|
||||
See also the [Update Guide](https://discordjs.guide/additional-info/changes-in-v13.html), including updated and removed items in the library.
|
||||
- [discord.js Discord server](https://discord.gg/djs)
|
||||
- [Discord API Discord server](https://discord.gg/discord-api)
|
||||
- [GitHub](https://github.com/discordjs/discord.js/tree/main/packages/proxy)
|
||||
- [npm](https://www.npmjs.com/package/@discordjs/proxy)
|
||||
- [Related libraries](https://discord.com/developers/docs/topics/community-resources#libraries)
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { REST } from '@discordjs/rest';
|
||||
import supertest from 'supertest';
|
||||
import { MockAgent, Interceptable, setGlobalDispatcher } from 'undici';
|
||||
import type { MockInterceptor } from 'undici/types/mock-interceptor';
|
||||
import { beforeEach, afterAll, afterEach, test, expect } from 'vitest';
|
||||
import { proxyRequests } from '../src';
|
||||
|
||||
let mockAgent: MockAgent;
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
/**
|
||||
* @type {import('@babel/core').TransformOptions}
|
||||
*/
|
||||
module.exports = {
|
||||
parserOpts: { strictMode: true },
|
||||
sourceMaps: 'inline',
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
targets: { node: 'current' },
|
||||
modules: 'commonjs',
|
||||
},
|
||||
],
|
||||
'@babel/preset-typescript',
|
||||
],
|
||||
};
|
||||
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* @type {import('@jest/types').Config.InitialOptions}
|
||||
*/
|
||||
module.exports = {
|
||||
testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'],
|
||||
testEnvironment: 'node',
|
||||
collectCoverage: true,
|
||||
collectCoverageFrom: ['src/**/*.ts'],
|
||||
coverageDirectory: 'coverage',
|
||||
coverageReporters: ['text', 'lcov', 'clover'],
|
||||
};
|
||||
@@ -4,10 +4,9 @@
|
||||
"description": "Tools for running an HTTP proxy for Discord's API",
|
||||
"scripts": {
|
||||
"build": "tsup && tsc --emitDeclarationOnly --incremental",
|
||||
"test": "jest --pass-with-no-tests --collect-coverage",
|
||||
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"docs": "typedoc --json docs/typedoc-out.json src/index.ts && node scripts/docs.mjs",
|
||||
"docs": "typedoc --json docs/typedoc-out.json src/index.ts && ts-docgen -i docs/typedoc-out.json -c docs/index.yml -o docs/docs.json",
|
||||
"prepublishOnly": "yarn build && yarn lint && yarn test",
|
||||
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/proxy/*'"
|
||||
},
|
||||
@@ -57,23 +56,15 @@
|
||||
"undici": "^5.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.18.2",
|
||||
"@babel/plugin-proposal-decorators": "^7.18.2",
|
||||
"@babel/preset-env": "^7.18.2",
|
||||
"@babel/preset-typescript": "^7.17.12",
|
||||
"@discordjs/ts-docgen": "^0.4.1",
|
||||
"@types/jest": "^28.1.0",
|
||||
"@discordjs/scripts": "workspace:^",
|
||||
"@types/node": "^16.11.38",
|
||||
"@types/supertest": "^2.0.12",
|
||||
"@typescript-eslint/eslint-plugin": "^5.27.0",
|
||||
"@typescript-eslint/parser": "^5.27.0",
|
||||
"babel-plugin-const-enum": "^1.2.0",
|
||||
"babel-plugin-transform-typescript-metadata": "^0.3.2",
|
||||
"eslint": "^8.17.0",
|
||||
"eslint-config-marine": "^9.4.1",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"jest": "^28.1.0",
|
||||
"prettier": "^2.6.2",
|
||||
"supertest": "^6.2.3",
|
||||
"tsup": "^6.0.1",
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import { runGenerator } from '@discordjs/ts-docgen';
|
||||
|
||||
runGenerator({
|
||||
existingOutput: 'docs/typedoc-out.json',
|
||||
custom: 'docs/index.yml',
|
||||
output: 'docs/docs.json',
|
||||
});
|
||||
@@ -74,7 +74,9 @@ try {
|
||||
## Links
|
||||
|
||||
- [Website](https://discord.js.org/) ([source](https://github.com/discordjs/website))
|
||||
- [Dev documentation](https://discord.js.org/#/docs/rest/main/general/welcome) (stable coming soon)
|
||||
- [Documentation](https://discord.js.org/#/docs/rest)
|
||||
- [Guide](https://discordjs.guide/) ([source](https://github.com/discordjs/guide))
|
||||
See also the [Update Guide](https://discordjs.guide/additional-info/changes-in-v13.html), including updated and removed items in the library.
|
||||
- [discord.js Discord server](https://discord.gg/djs)
|
||||
- [Discord API Discord server](https://discord.gg/discord-api)
|
||||
- [GitHub](https://github.com/discordjs/discord.js/tree/main/packages/rest)
|
||||
@@ -84,7 +86,7 @@ try {
|
||||
## Contributing
|
||||
|
||||
Before creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the
|
||||
[documentation](https://discord.js.org/#/docs/rest/main/general/welcome).
|
||||
[documentation](https://discord.js.org/#/docs/rest).
|
||||
See [the contribution guide](https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md) if you'd like to submit a PR.
|
||||
|
||||
## Help
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { test, expect } from 'vitest';
|
||||
import { CDN } from '../src';
|
||||
|
||||
const base = 'https://discord.com';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { test, expect } from 'vitest';
|
||||
import { DiscordAPIError } from '../src';
|
||||
|
||||
test('Unauthorized', () => {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { DiscordSnowflake } from '@sapphire/snowflake';
|
||||
import { Routes, Snowflake } from 'discord-api-types/v10';
|
||||
import { File, FormData, MockAgent, setGlobalDispatcher } from 'undici';
|
||||
import type { Interceptable, MockInterceptor } from 'undici/types/mock-interceptor';
|
||||
import { beforeEach, afterEach, test, expect } from 'vitest';
|
||||
import { genPath } from './util';
|
||||
import { REST } from '../src';
|
||||
|
||||
@@ -107,7 +108,7 @@ test('simple POST', async () => {
|
||||
expect(await api.post('/simplePost')).toStrictEqual({ test: true });
|
||||
});
|
||||
|
||||
test('simple PUT', async () => {
|
||||
test('simple PUT 2', async () => {
|
||||
mockPool
|
||||
.intercept({
|
||||
path: genPath('/simplePut'),
|
||||
@@ -285,7 +286,7 @@ test('Old Message Delete Edge-Case: Old message', async () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('Old Message Delete Edge-Case: Old message', async () => {
|
||||
test('Old Message Delete Edge-Case: Old message 2', async () => {
|
||||
mockPool
|
||||
.intercept({
|
||||
path: genPath(`/channels/339942739275677727/messages/${newSnowflake}`),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { performance } from 'node:perf_hooks';
|
||||
import { MockAgent, setGlobalDispatcher } from 'undici';
|
||||
import type { Interceptable, MockInterceptor } from 'undici/types/mock-interceptor';
|
||||
import { beforeEach, afterEach, test, expect, vitest } from 'vitest';
|
||||
import { genPath } from './util';
|
||||
import { DiscordAPIError, HTTPError, RateLimitError, REST, RESTEvents } from '../src';
|
||||
|
||||
@@ -82,8 +83,8 @@ test('Significant Invalid Requests', async () => {
|
||||
.reply(403, { message: 'Missing Permissions', code: 50013 }, responseOptions)
|
||||
.times(10);
|
||||
|
||||
const invalidListener = jest.fn();
|
||||
const invalidListener2 = jest.fn();
|
||||
const invalidListener = vitest.fn();
|
||||
const invalidListener2 = vitest.fn();
|
||||
api.on(RESTEvents.InvalidRequestWarning, invalidListener);
|
||||
// Ensure listeners on REST do not get double added
|
||||
api.on(RESTEvents.InvalidRequestWarning, invalidListener2);
|
||||
@@ -364,6 +365,7 @@ test('Handle unexpected 429', async () => {
|
||||
expect(await unexepectedSublimit).toStrictEqual({ test: true });
|
||||
expect(await queuedSublimit).toStrictEqual({ test: true });
|
||||
expect(performance.now()).toBeGreaterThanOrEqual(previous + 1000);
|
||||
// @ts-expect-error
|
||||
expect(secondResolvedTime).toBeGreaterThan(firstResolvedTime);
|
||||
});
|
||||
|
||||
@@ -495,7 +497,7 @@ test('Unauthorized', async () => {
|
||||
.reply(401, { message: '401: Unauthorized', code: 0 }, responseOptions)
|
||||
.times(2);
|
||||
|
||||
const setTokenSpy = jest.spyOn(invalidAuthApi.requestManager, 'setToken');
|
||||
const setTokenSpy = vitest.spyOn(invalidAuthApi.requestManager, 'setToken');
|
||||
|
||||
// Ensure authless requests don't reset the token
|
||||
const promiseWithoutTokenClear = invalidAuthApi.get('/unauthorized', { auth: false });
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { MockAgent, setGlobalDispatcher } from 'undici';
|
||||
import { Interceptable } from 'undici/types/mock-interceptor';
|
||||
import type { Interceptable } from 'undici/types/mock-interceptor';
|
||||
import { beforeEach, afterEach, test, expect } from 'vitest';
|
||||
import { genPath } from './util';
|
||||
import { REST } from '../src';
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Blob } from 'node:buffer';
|
||||
import { test, expect } from 'vitest';
|
||||
import { resolveBody, parseHeader } from '../src/lib/utils/utils';
|
||||
|
||||
test('GIVEN string parseHeader returns string', () => {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { makeURLSearchParams } from '../src';
|
||||
|
||||
describe('makeURLSearchParams', () => {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user