mirror of
https://github.com/discordjs/discord.js.git
synced 2026-05-23 03:50:09 +00:00
Compare commits
32 Commits
14.22.1
...
@discordjs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f65ff060ae | ||
|
|
835c4496ab | ||
|
|
a589c6d492 | ||
|
|
fdf0b8455c | ||
|
|
3f9c3dc497 | ||
|
|
437b2d459d | ||
|
|
5b8a08ebb6 | ||
|
|
22e013b3e9 | ||
|
|
e133aa9a1e | ||
|
|
c1b5242d2f | ||
|
|
9779baea84 | ||
|
|
a5437a41f3 | ||
|
|
11dd1c0666 | ||
|
|
95fae30606 | ||
|
|
93eeaeb56b | ||
|
|
886a701251 | ||
|
|
6dc0b7c18a | ||
|
|
c4eba873ea | ||
|
|
5c023bd64b | ||
|
|
e7cc754fd3 | ||
|
|
6e32ee565f | ||
|
|
c6710e56cc | ||
|
|
5761f2cbfd | ||
|
|
dd9ba1ad9d | ||
|
|
0b0abfa283 | ||
|
|
419266d839 | ||
|
|
5e7ba2a016 | ||
|
|
efd6b36227 | ||
|
|
66774c1b53 | ||
|
|
728c2686bd | ||
|
|
1bafba3fff | ||
|
|
a193147f96 |
@@ -5,7 +5,7 @@
|
||||
"type-enum": [
|
||||
2,
|
||||
"always",
|
||||
["chore", "build", "ci", "docs", "feat", "fix", "perf", "refactor", "revert", "style", "test", "types", "typings"]
|
||||
["chore", "build", "ci", "docs", "feat", "fix", "perf", "refactor", "revert", "style", "test", "types"]
|
||||
],
|
||||
"scope-case": [0]
|
||||
}
|
||||
|
||||
2
.github/COMMIT_CONVENTION.md
vendored
2
.github/COMMIT_CONVENTION.md
vendored
@@ -7,7 +7,7 @@
|
||||
Messages must be matched by the following regex:
|
||||
|
||||
```js
|
||||
/^(revert: )?(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|types|wip)(\(.+\))?: .{1,72}/;
|
||||
/^(revert: )?(feat|fix|docs|style|refactor|perf|test|build|ci|chore|types)(\(.+\))?: .{1,72}/;
|
||||
```
|
||||
|
||||
#### Examples
|
||||
|
||||
80
.github/labeler.yml
vendored
80
.github/labeler.yml
vendored
@@ -1,60 +1,100 @@
|
||||
apps:guide:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['apps/guide/*', 'apps/guide/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- apps/guide/*
|
||||
- apps/guide/**/*
|
||||
apps:website:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['apps/website/*', 'apps/website/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- apps/website/*
|
||||
- apps/website/**/*
|
||||
packages:api-extractor:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/api-extractor/*', 'packages/api-extractor/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- packages/api-extractor/*
|
||||
- packages/api-extractor/**/*
|
||||
packages:api-extractor-model:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/api-extractor-model/*', 'packages/api-extractor-model/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- packages/api-extractor-model/*
|
||||
- packages/api-extractor-model/**/*
|
||||
packages:brokers:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/brokers/*', 'packages/brokers/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- packages/brokers/*
|
||||
- packages/brokers/**/*
|
||||
packages:builders:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/builders/*', 'packages/builders/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- packages/builders/*
|
||||
- packages/builders/**/*
|
||||
packages:collection:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/collection/*', 'packages/collection/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- packages/collection/*
|
||||
- packages/collection/**/*
|
||||
packages:core:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/core/*', 'packages/core/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- packages/core/*
|
||||
- packages/core/**/*
|
||||
packages:create-discord-bot:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/create-discord-bot/*', 'packages/create-discord-bot/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- packages/create-discord-bot/*
|
||||
- packages/create-discord-bot/**/*
|
||||
packages:discord.js:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/discord.js/*', 'packages/discord.js/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- packages/discord.js/*
|
||||
- packages/discord.js/**/*
|
||||
packages:docgen:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/docgen/*', 'packages/docgen/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- packages/docgen/*
|
||||
- packages/docgen/**/*
|
||||
packages:formatters:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/formatters/*', 'packages/formatters/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- packages/formatters/*
|
||||
- packages/formatters/**/*
|
||||
packages:next:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/next/*', 'packages/next/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- packages/next/*
|
||||
- packages/next/**/*
|
||||
packages:proxy:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/proxy/*', 'packages/proxy/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- packages/proxy/*
|
||||
- packages/proxy/**/*
|
||||
packages:proxy-container:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/proxy-container/*', 'packages/proxy-container/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- packages/proxy-container/*
|
||||
- packages/proxy-container/**/*
|
||||
packages:rest:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/rest/*', 'packages/rest/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- packages/rest/*
|
||||
- packages/rest/**/*
|
||||
packages:ui:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/ui/*', 'packages/ui/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- packages/ui/*
|
||||
- packages/ui/**/*
|
||||
packages:util:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/util/*', 'packages/util/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- packages/util/*
|
||||
- packages/util/**/*
|
||||
packages:voice:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/voice/*', 'packages/voice/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- packages/voice/*
|
||||
- packages/voice/**/*
|
||||
packages:ws:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/ws/*', 'packages/ws/**/*']
|
||||
- any-glob-to-any-file:
|
||||
- packages/ws/*
|
||||
- packages/ws/**/*
|
||||
|
||||
28
.github/workflows/pr-triage.yml
vendored
28
.github/workflows/pr-triage.yml
vendored
@@ -1,13 +1,35 @@
|
||||
name: 'PR Triage'
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- reopened
|
||||
- synchronize
|
||||
jobs:
|
||||
pr-triage:
|
||||
name: PR Triage
|
||||
label:
|
||||
name: Label
|
||||
if: github.event.action != 'edited'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Automatically label PR
|
||||
- name: Label pull request
|
||||
uses: actions/labeler@v5
|
||||
with:
|
||||
repo-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
sync-labels: true
|
||||
validate-title:
|
||||
name: Validate title
|
||||
if: github.event.action != 'synchronize'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Validate pull request title
|
||||
env:
|
||||
TITLE: ${{ github.event.pull_request.title }}
|
||||
run: |
|
||||
REGEX="^(revert: )?(feat|fix|docs|style|refactor|perf|test|build|ci|chore|types)(\\(.+\\))?: .{1,72}$"
|
||||
|
||||
echo "Title: \"$TITLE\""
|
||||
|
||||
if [[ ! "$TITLE" =~ $REGEX ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
"@code-hike/mdx": "^0.9.0",
|
||||
"@discordjs/ui": "workspace:^",
|
||||
"@react-icons/all-files": "^4.1.0",
|
||||
"@vercel/analytics": "^1.2.2",
|
||||
"@vercel/edge-config": "^1.1.0",
|
||||
"@vercel/analytics": "^1.3.1",
|
||||
"@vercel/edge-config": "^1.1.1",
|
||||
"@vercel/og": "^0.6.2",
|
||||
"ariakit": "2.0.0-next.44",
|
||||
"cmdk": "^1.0.0",
|
||||
@@ -72,26 +72,26 @@
|
||||
"@types/node": "18.18.8",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@unocss/eslint-plugin": "^0.60.2",
|
||||
"@unocss/postcss": "^0.60.2",
|
||||
"@unocss/reset": "^0.60.2",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"@unocss/eslint-plugin": "^0.60.4",
|
||||
"@unocss/postcss": "^0.60.4",
|
||||
"@unocss/reset": "^0.60.4",
|
||||
"@vitejs/plugin-react": "^4.3.0",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"happy-dom": "^14.11.0",
|
||||
"happy-dom": "^14.12.0",
|
||||
"hast-util-to-string": "^2.0.0",
|
||||
"hastscript": "^8.0.0",
|
||||
"html-escaper": "^3.0.3",
|
||||
"postcss": "^8.4.38",
|
||||
"prettier": "^3.2.5",
|
||||
"turbo": "^1.13.2",
|
||||
"prettier": "^3.3.0",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5",
|
||||
"unocss": "^0.60.2",
|
||||
"vercel": "^34.0.0",
|
||||
"vitest": "^1.5.0"
|
||||
"unocss": "^0.60.4",
|
||||
"vercel": "^34.2.4",
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
||||
@@ -134,8 +134,8 @@ collector.on('end', (collected) => {
|
||||
|
||||
### Await reactions
|
||||
|
||||
<DocsLink type="class" parent="Message" symbol="awaitReactions" brackets /> works almost the same as a reaction collector,
|
||||
except it is Promise-based. The same differences apply as with channel collectors.
|
||||
<DocsLink type="class" parent="Message" symbol="awaitReactions" brackets /> works almost the same as a reaction
|
||||
collector, except it is Promise-based. The same differences apply as with channel collectors.
|
||||
|
||||
```js
|
||||
const collectorFilter = (reaction, user) => {
|
||||
|
||||
@@ -158,21 +158,25 @@ Various _`create()`_ and _`edit()`_ methods on managers and objects have had the
|
||||
- <DocsLink type="class" parent="Role" symbol="edit" brackets /> now takes _`reason`_ in the _`data`_ parameter
|
||||
- <DocsLink type="class" parent="Sticker" symbol="edit" brackets /> now takes _`reason`_ in the _`data`_ parameter
|
||||
- <DocsLink type="class" parent="ThreadChannel" symbol="edit" brackets /> now takes _`reason`_ in the _`data`_ parameter
|
||||
- <DocsLink type="class" parent="GuildChannelManager" symbol="create" brackets /> now takes _`name`_ in the _`options`_ parameter
|
||||
- <DocsLink type="class" parent="GuildChannelManager" symbol="create" brackets /> now takes _`name`_ in the _`options`_
|
||||
parameter
|
||||
- <DocsLink type="class" parent="GuildChannelManager" symbol="createWebhook" brackets /> (and other text-based channels)
|
||||
now takes _`channel`_ and _`name`_ in the _`options`_ parameter
|
||||
- <DocsLink type="class" parent="GuildChannelManager" symbol="edit" brackets /> now takes _`reason`_ as a part of _`data`_
|
||||
- <DocsLink type="class" parent="GuildChannelManager" symbol="edit" brackets /> now takes _`reason`_ as a part of
|
||||
_`data`_
|
||||
- <DocsLink type="class" parent="GuildEmojiManager" symbol="edit" brackets /> now takes _`reason`_ as a part of _`data`_
|
||||
- <DocsLink type="class" parent="GuildManager" symbol="create" brackets /> now takes _`name`_ as a part of _`options`_
|
||||
- <DocsLink type="class" parent="GuildMemberManager" symbol="edit" brackets /> now takes _`reason`_ as a part of _`data`_
|
||||
- <DocsLink type="class" parent="GuildMemberManager" symbol="edit" brackets /> now takes _`reason`_ as a part of
|
||||
_`data`_
|
||||
- <DocsLink type="class" parent="GuildMember" symbol="edit" brackets /> now takes _`reason`_ as a part of _`data`_
|
||||
- <DocsLink type="class" parent="GuildStickerManager" symbol="edit" brackets /> now takes _`reason`_ as a part of _`data`_
|
||||
- <DocsLink type="class" parent="GuildStickerManager" symbol="edit" brackets /> now takes _`reason`_ as a part of
|
||||
_`data`_
|
||||
- <DocsLink type="class" parent="RoleManager" symbol="edit" brackets /> now takes _`reason`_ as a part of _`options`_
|
||||
- <DocsLink type="class" parent="Webhook" symbol="edit" brackets /> now takes _`reason`_ as a part of _`options`_
|
||||
- <DocsLink type="class" parent="GuildEmojiManager" symbol="create" brackets /> now takes _`attachment`_ and _`name`_ as
|
||||
a part of _`options`_
|
||||
- <DocsLink type="class" parent="GuildStickerManager" symbol="create" brackets /> now takes _`file`_, _`name`_, and _`tags`_
|
||||
as a part of _`options`_
|
||||
- <DocsLink type="class" parent="GuildStickerManager" symbol="create" brackets /> now takes _`file`_, _`name`_, and
|
||||
_`tags`_ as a part of _`options`_
|
||||
|
||||
### Activity
|
||||
|
||||
@@ -236,9 +240,10 @@ Dynamic URLs use <DocsLink package="rest" type="Interface" parent="ImageURLOptio
|
||||
|
||||
### CategoryChannel
|
||||
|
||||
<DocsLink type="class" parent="CategoryChannel" symbol="children" /> is no longer a _`Collection`_ of channels the category
|
||||
contains. It is now a <DocsLink type="class" parent="CategoryChannelChildManager" />. This also means
|
||||
_`CategoryChannel#createChannel()`_ has been moved to the <DocsLink type="class" parent="CategoryChannelChildManager" />.
|
||||
<DocsLink type="class" parent="CategoryChannel" symbol="children" /> is no longer a _`Collection`_ of channels the
|
||||
category contains. It is now a <DocsLink type="class" parent="CategoryChannelChildManager" />. This also means
|
||||
_`CategoryChannel#createChannel()`_ has been moved to the <DocsLink type="class" parent="CategoryChannelChildManager" />
|
||||
.
|
||||
|
||||
### Channel
|
||||
|
||||
@@ -262,8 +267,8 @@ The _`restWsBridgeTimeout`_ client option has been removed.
|
||||
|
||||
### CommandInteractionOptionResolver
|
||||
|
||||
<DocsLink type="class" parent="CommandInteractionOptionResolver" symbol="getMember" brackets /> no longer has a parameter
|
||||
for _`required`_.[^1]
|
||||
<DocsLink type="class" parent="CommandInteractionOptionResolver" symbol="getMember" brackets /> no longer has a
|
||||
parameter for _`required`_.[^1]
|
||||
|
||||
### Constants
|
||||
|
||||
@@ -357,7 +362,8 @@ The following properties & methods have been moved to the <DocsLink type="class"
|
||||
|
||||
### GuildMember
|
||||
|
||||
<DocsLink type="class" parent="GuildMember" symbol="pending" /> is now nullable to account for partial guild members.[^4]
|
||||
<DocsLink type="class" parent="GuildMember" symbol="pending" /> is now nullable to account for partial guild
|
||||
members.[^4]
|
||||
|
||||
### IntegrationApplication
|
||||
|
||||
@@ -582,8 +588,8 @@ _`Role.comparePositions()`_ has been removed. Use <DocsLink type="class" parent=
|
||||
|
||||
### Sticker
|
||||
|
||||
<DocsLink type="class" parent="Sticker" symbol="tags" /> is now a nullable string (_`string | null`_). Previously, it was
|
||||
a nullable array of strings (_`string[] | null`_).[^5]
|
||||
<DocsLink type="class" parent="Sticker" symbol="tags" /> is now a nullable string (_`string | null`_). Previously, it
|
||||
was a nullable array of strings (_`string[] | null`_).[^5]
|
||||
|
||||
### ThreadChannel
|
||||
|
||||
@@ -668,8 +674,8 @@ Added support for <DocsLink type="class" parent="BaseChannel" symbol="flags" />.
|
||||
|
||||
Store channels have been removed as they are no longer part of the API.
|
||||
|
||||
<DocsLink type="class" parent="BaseChannel" symbol="url" /> has been added which is a link to a channel, just like in the
|
||||
client.
|
||||
<DocsLink type="class" parent="BaseChannel" symbol="url" /> has been added which is a link to a channel, just like in
|
||||
the client.
|
||||
|
||||
Additionally, new typeguards have been added:
|
||||
|
||||
@@ -713,13 +719,13 @@ Component collector options now use the <DiscordAPITypesLink type="enum" parent=
|
||||
|
||||
### CommandInteraction
|
||||
|
||||
<DocsLink type="class" parent="CommandInteraction" symbol="commandGuildId" /> has been added which is the id of the guild
|
||||
the invoked application command is registered to.
|
||||
<DocsLink type="class" parent="CommandInteraction" symbol="commandGuildId" /> has been added which is the id of the
|
||||
guild the invoked application command is registered to.
|
||||
|
||||
### CommandInteractionOptionResolver
|
||||
|
||||
<DocsLink type="class" parent="CommandInteractionOptionResolver" symbol="getChannel" brackets /> now has a third parameter
|
||||
which narrows the channel type.
|
||||
<DocsLink type="class" parent="CommandInteractionOptionResolver" symbol="getChannel" brackets /> now has a third
|
||||
parameter which narrows the channel type.
|
||||
|
||||
### Events
|
||||
|
||||
@@ -814,9 +820,15 @@ Added the _`threadName`_ property in <DocsLink type="typedef" parent="WebhookMes
|
||||
discord.js uses <DocsLink package="ws" /> internally.
|
||||
|
||||
[^1]: https://github.com/discordjs/discord.js/pull/7188
|
||||
|
||||
[^2]: https://github.com/discordjs/discord.js/pull/6492
|
||||
|
||||
[^3]: https://github.com/discordjs/discord.js/pull/7669
|
||||
|
||||
[^4]: https://github.com/discordjs/discord.js/issues/6546
|
||||
|
||||
[^5]: https://github.com/discordjs/discord.js/pull/8010
|
||||
|
||||
[^6]: https://github.com/discordjs/discord.js/issues/7091
|
||||
|
||||
[^7]: https://github.com/discord/discord-api-docs/pull/6017
|
||||
|
||||
@@ -49,37 +49,37 @@
|
||||
"dependencies": {
|
||||
"@radix-ui/react-collapsible": "^1.0.3",
|
||||
"@react-icons/all-files": "^4.1.0",
|
||||
"@vercel/analytics": "^1.3.0",
|
||||
"@vercel/analytics": "^1.3.1",
|
||||
"@vercel/blob": "^0.23.3",
|
||||
"@vercel/edge-config": "^1.1.1",
|
||||
"@vercel/og": "^0.6.2",
|
||||
"@vercel/postgres": "^0.8.0",
|
||||
"cmdk": "^1.0.0",
|
||||
"geist": "^1.3.0",
|
||||
"jotai": "^2.8.1",
|
||||
"jotai": "^2.8.2",
|
||||
"lucide-react": "^0.379.0",
|
||||
"meilisearch": "^0.40.0",
|
||||
"next": "^15.0.0-rc.0",
|
||||
"next-mdx-remote-client": "^1.0.3",
|
||||
"next-themes": "^0.3.0",
|
||||
"overlayscrollbars": "^2.8.2",
|
||||
"overlayscrollbars": "^2.8.3",
|
||||
"overlayscrollbars-react": "^0.5.6",
|
||||
"react": "^19.0.0-rc-4c2e457c7c-20240522",
|
||||
"react": "19.0.0-rc-f994737d14-20240522",
|
||||
"react-aria-components": "^1.2.1",
|
||||
"react-dom": "^19.0.0-rc-4c2e457c7c-20240522",
|
||||
"react-dom": "19.0.0-rc-f994737d14-20240522",
|
||||
"sharp": "^0.33.4",
|
||||
"usehooks-ts": "^3.1.0",
|
||||
"vaul": "^0.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@shikijs/rehype": "^1.6.0",
|
||||
"@shikijs/rehype": "^1.6.2",
|
||||
"@tailwindcss/typography": "^0.5.13",
|
||||
"@testing-library/react": "^15.0.7",
|
||||
"@testing-library/user-event": "^14.5.2",
|
||||
"@types/node": "18.18.8",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"@vitejs/plugin-react": "^4.3.0",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"babel-plugin-react-compiler": "0.0.0-experimental-592953e-20240517",
|
||||
@@ -88,18 +88,18 @@
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"happy-dom": "^14.11.0",
|
||||
"happy-dom": "^14.12.0",
|
||||
"postcss": "^8.4.38",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier": "^3.3.0",
|
||||
"prettier-plugin-tailwindcss": "^0.5.14",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"remark-rehype": "^11.1.0",
|
||||
"shiki": "^1.6.0",
|
||||
"shiki": "^1.6.2",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"turbo": "^1.13.2",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5",
|
||||
"vercel": "^34.2.2",
|
||||
"vitest": "^1.5.0"
|
||||
"vercel": "^34.2.4",
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
||||
@@ -30,7 +30,7 @@ export async function DocNode({ node, version }: { readonly node?: any; readonly
|
||||
rel="external noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
{`${node.text}${node.members}`}
|
||||
{`${node.text}${node.members ?? ''}`}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
28
package.json
28
package.json
@@ -50,28 +50,28 @@
|
||||
"homepage": "https://discord.js.org",
|
||||
"funding": "https://github.com/discordjs/discord.js?sponsor",
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^19.2.2",
|
||||
"@commitlint/config-angular": "^19.2.2",
|
||||
"@favware/cliff-jumper": "^3.0.2",
|
||||
"@commitlint/cli": "^19.3.0",
|
||||
"@commitlint/config-angular": "^19.3.0",
|
||||
"@favware/cliff-jumper": "^3.0.3",
|
||||
"@favware/npm-deprecate": "^1.0.7",
|
||||
"@types/lodash.merge": "^4.6.9",
|
||||
"@unocss/eslint-plugin": "^0.59.3",
|
||||
"@vitest/coverage-v8": "^1.5.0",
|
||||
"@unocss/eslint-plugin": "^0.59.4",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"conventional-changelog-cli": "^4.1.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"husky": "^9.0.11",
|
||||
"is-ci": "^3.0.1",
|
||||
"lint-staged": "^15.2.2",
|
||||
"lint-staged": "^15.2.5",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"prettier": "^3.2.5",
|
||||
"tsup": "^8.0.2",
|
||||
"turbo": "^1.13.2",
|
||||
"prettier": "^3.3.0",
|
||||
"tsup": "^8.1.0",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5",
|
||||
"typescript-eslint": "^7.7.0",
|
||||
"unocss": "^0.60.2",
|
||||
"vercel": "^34.0.0",
|
||||
"vitest": "^1.5.0"
|
||||
"typescript-eslint": "^7.11.0",
|
||||
"unocss": "^0.60.4",
|
||||
"vercel": "^34.2.4",
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"pnpm": {
|
||||
"peerDependencyRules": {
|
||||
@@ -97,5 +97,5 @@
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"packageManager": "pnpm@9.1.1"
|
||||
"packageManager": "pnpm@9.1.4"
|
||||
}
|
||||
|
||||
@@ -49,20 +49,20 @@
|
||||
"meilisearch": "^0.38.0",
|
||||
"p-limit": "^5.0.0",
|
||||
"tslib": "^2.6.2",
|
||||
"undici": "6.13.0"
|
||||
"undici": "6.18.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "18.18.8",
|
||||
"@vitest/coverage-v8": "^1.5.0",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"prettier": "^3.2.5",
|
||||
"tsup": "^8.0.2",
|
||||
"turbo": "^1.13.2",
|
||||
"prettier": "^3.3.0",
|
||||
"tsup": "^8.1.0",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5",
|
||||
"vitest": "^1.5.0"
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
||||
@@ -11,6 +11,7 @@ runs:
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: ./apps/guide/coverage/cobertura-coverage.xml
|
||||
disable_search: true
|
||||
flags: guide
|
||||
token: ${{ inputs.CODECOV_TOKEN }}
|
||||
|
||||
@@ -18,6 +19,7 @@ runs:
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: ./apps/website/coverage/cobertura-coverage.xml
|
||||
disable_search: true
|
||||
flags: website
|
||||
token: ${{ inputs.CODECOV_TOKEN }}
|
||||
|
||||
@@ -25,6 +27,7 @@ runs:
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: ./packages/brokers/coverage/cobertura-coverage.xml
|
||||
disable_search: true
|
||||
flags: brokers
|
||||
token: ${{ inputs.CODECOV_TOKEN }}
|
||||
|
||||
@@ -32,6 +35,7 @@ runs:
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: ./packages/builders/coverage/cobertura-coverage.xml
|
||||
disable_search: true
|
||||
flags: builders
|
||||
token: ${{ inputs.CODECOV_TOKEN }}
|
||||
|
||||
@@ -39,6 +43,7 @@ runs:
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: ./packages/collection/coverage/cobertura-coverage.xml
|
||||
disable_search: true
|
||||
flags: collection
|
||||
token: ${{ inputs.CODECOV_TOKEN }}
|
||||
|
||||
@@ -46,6 +51,7 @@ runs:
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: ./packages/discord.js/coverage/cobertura-coverage.xml
|
||||
disable_search: true
|
||||
flags: discord.js
|
||||
token: ${{ inputs.CODECOV_TOKEN }}
|
||||
|
||||
@@ -53,6 +59,7 @@ runs:
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: ./packages/formatters/coverage/cobertura-coverage.xml
|
||||
disable_search: true
|
||||
flags: formatters
|
||||
token: ${{ inputs.CODECOV_TOKEN }}
|
||||
|
||||
@@ -60,6 +67,7 @@ runs:
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: ./packages/next/coverage/cobertura-coverage.xml
|
||||
disable_search: true
|
||||
flags: next
|
||||
token: ${{ inputs.CODECOV_TOKEN }}
|
||||
|
||||
@@ -67,6 +75,7 @@ runs:
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: ./packages/proxy/coverage/cobertura-coverage.xml
|
||||
disable_search: true
|
||||
flags: proxy
|
||||
token: ${{ inputs.CODECOV_TOKEN }}
|
||||
|
||||
@@ -74,6 +83,7 @@ runs:
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: ./packages/rest/coverage/cobertura-coverage.xml
|
||||
disable_search: true
|
||||
flags: rest
|
||||
token: ${{ inputs.CODECOV_TOKEN }}
|
||||
|
||||
@@ -81,6 +91,7 @@ runs:
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: ./packages/voice/coverage/cobertura-coverage.xml
|
||||
disable_search: true
|
||||
flags: voice
|
||||
token: ${{ inputs.CODECOV_TOKEN }}
|
||||
|
||||
@@ -88,6 +99,7 @@ runs:
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: ./packages/ws/coverage/cobertura-coverage.xml
|
||||
disable_search: true
|
||||
flags: ws
|
||||
token: ${{ inputs.CODECOV_TOKEN }}
|
||||
|
||||
@@ -95,6 +107,7 @@ runs:
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: ./packages/util/coverage/cobertura-coverage.xml
|
||||
disable_search: true
|
||||
flags: util
|
||||
token: ${{ inputs.CODECOV_TOKEN }}
|
||||
|
||||
@@ -102,5 +115,6 @@ runs:
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: ./packages/actions/coverage/cobertura-coverage.xml, ./packages/scripts/coverage/cobertura-coverage.xml
|
||||
disable_search: true
|
||||
flags: utilities
|
||||
token: ${{ inputs.CODECOV_TOKEN }}
|
||||
|
||||
@@ -37,14 +37,14 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/node": "^18.19.22",
|
||||
"@types/node": "^18.19.33",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.2.5",
|
||||
"tsup": "^8.0.2",
|
||||
"turbo": "^1.13.2"
|
||||
"prettier": "^3.3.0",
|
||||
"tsup": "^8.1.0",
|
||||
"turbo": "^1.13.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +115,7 @@ export class ModelReferenceResolver {
|
||||
if (memberSelector === undefined) {
|
||||
if (foundMembers.length > 1) {
|
||||
const foundClass: ApiItem | undefined = foundMembers.find((member) => member.kind === ApiItemKind.Class);
|
||||
const foundEvent: ApiItem | undefined = foundMembers.find((member) => member.kind === ApiItemKind.Event);
|
||||
if (
|
||||
foundClass &&
|
||||
foundMembers.filter((member) => member.kind === ApiItemKind.Interface).length === foundMembers.length - 1
|
||||
@@ -124,6 +125,11 @@ export class ModelReferenceResolver {
|
||||
foundMembers.every((member) => member.kind === ApiItemKind.Method && (member as ApiMethod).overloadIndex)
|
||||
) {
|
||||
currentItem = foundMembers.find((member) => (member as ApiMethod).overloadIndex === 1)!;
|
||||
} else if (
|
||||
foundEvent &&
|
||||
foundMembers.filter((member) => member.kind === ApiItemKind.Method).length === foundMembers.length - 1
|
||||
) {
|
||||
currentItem = foundEvent;
|
||||
} else {
|
||||
result.errorMessage = `The member reference ${JSON.stringify(identifier)} was ambiguous`;
|
||||
return result;
|
||||
|
||||
@@ -55,9 +55,9 @@
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"prettier": "^3.2.5",
|
||||
"tsup": "^8.0.2",
|
||||
"turbo": "^1.13.2",
|
||||
"prettier": "^3.3.0",
|
||||
"tsup": "^8.1.0",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -65,8 +65,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/lodash": "^4.17.0",
|
||||
"@types/node": "^18.19.22",
|
||||
"@types/lodash": "^4.17.4",
|
||||
"@types/node": "^18.19.33",
|
||||
"@types/resolve": "^1.20.6",
|
||||
"@types/semver": "^7.5.8",
|
||||
"cpy-cli": "^5.0.0",
|
||||
@@ -75,8 +75,8 @@
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.2.5",
|
||||
"tsup": "^8.0.2",
|
||||
"turbo": "^1.13.2"
|
||||
"prettier": "^3.3.0",
|
||||
"tsup": "^8.1.0",
|
||||
"turbo": "^1.13.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,24 +69,24 @@
|
||||
"dependencies": {
|
||||
"@msgpack/msgpack": "^3.0.0-beta2",
|
||||
"@vladfrangu/async_event_emitter": "^2.2.4",
|
||||
"ioredis": "^5.3.2"
|
||||
"ioredis": "^5.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@discordjs/api-extractor": "workspace:^",
|
||||
"@discordjs/scripts": "workspace:^",
|
||||
"@favware/cliff-jumper": "^3.0.2",
|
||||
"@favware/cliff-jumper": "^3.0.3",
|
||||
"@types/node": "18.18.8",
|
||||
"@vitest/coverage-v8": "^1.5.0",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"esbuild-plugin-version-injector": "^1.2.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"prettier": "^3.2.5",
|
||||
"tsup": "^8.0.2",
|
||||
"turbo": "^1.13.2",
|
||||
"prettier": "^3.3.0",
|
||||
"tsup": "^8.1.0",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5",
|
||||
"vitest": "^1.5.0"
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
||||
@@ -50,6 +50,11 @@ describe('Button Components', () => {
|
||||
button.toJSON();
|
||||
}).not.toThrowError();
|
||||
|
||||
expect(() => {
|
||||
const button = buttonComponent().setSKUId('123456789012345678').setStyle(ButtonStyle.Premium);
|
||||
button.toJSON();
|
||||
}).not.toThrowError();
|
||||
|
||||
expect(() => buttonComponent().setURL('https://google.com')).not.toThrowError();
|
||||
});
|
||||
|
||||
@@ -101,6 +106,47 @@ describe('Button Components', () => {
|
||||
button.toJSON();
|
||||
}).toThrowError();
|
||||
|
||||
expect(() => {
|
||||
const button = buttonComponent().setStyle(ButtonStyle.Primary).setSKUId('123456789012345678');
|
||||
button.toJSON();
|
||||
}).toThrowError();
|
||||
|
||||
expect(() => {
|
||||
const button = buttonComponent()
|
||||
.setStyle(ButtonStyle.Secondary)
|
||||
.setLabel('button')
|
||||
.setSKUId('123456789012345678');
|
||||
|
||||
button.toJSON();
|
||||
}).toThrowError();
|
||||
|
||||
expect(() => {
|
||||
const button = buttonComponent()
|
||||
.setStyle(ButtonStyle.Success)
|
||||
.setEmoji({ name: '😇' })
|
||||
.setSKUId('123456789012345678');
|
||||
|
||||
button.toJSON();
|
||||
}).toThrowError();
|
||||
|
||||
expect(() => {
|
||||
const button = buttonComponent()
|
||||
.setStyle(ButtonStyle.Danger)
|
||||
.setCustomId('test')
|
||||
.setSKUId('123456789012345678');
|
||||
|
||||
button.toJSON();
|
||||
}).toThrowError();
|
||||
|
||||
expect(() => {
|
||||
const button = buttonComponent()
|
||||
.setStyle(ButtonStyle.Link)
|
||||
.setURL('https://google.com')
|
||||
.setSKUId('123456789012345678');
|
||||
|
||||
button.toJSON();
|
||||
}).toThrowError();
|
||||
|
||||
// @ts-expect-error: Invalid style
|
||||
expect(() => buttonComponent().setStyle(24)).toThrowError();
|
||||
expect(() => buttonComponent().setLabel(longStr)).toThrowError();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PermissionFlagsBits } from 'discord-api-types/v10';
|
||||
import { ApplicationIntegrationType, InteractionContextType, PermissionFlagsBits } from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { ContextMenuCommandAssertions, ContextMenuCommandBuilder } from '../../src/index.js';
|
||||
|
||||
@@ -144,5 +144,51 @@ describe('Context Menu Commands', () => {
|
||||
expect(() => getBuilder().setDefaultMemberPermissions(1.1)).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('contexts', () => {
|
||||
test('GIVEN a builder with valid contexts THEN does not throw an error', () => {
|
||||
expect(() =>
|
||||
getBuilder().setContexts([InteractionContextType.Guild, InteractionContextType.BotDM]),
|
||||
).not.toThrowError();
|
||||
|
||||
expect(() =>
|
||||
getBuilder().setContexts(InteractionContextType.Guild, InteractionContextType.BotDM),
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN a builder with invalid contexts THEN does throw an error', () => {
|
||||
// @ts-expect-error: Invalid contexts
|
||||
expect(() => getBuilder().setContexts(999)).toThrowError();
|
||||
|
||||
// @ts-expect-error: Invalid contexts
|
||||
expect(() => getBuilder().setContexts([999, 998])).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('integration types', () => {
|
||||
test('GIVEN a builder with valid integraton types THEN does not throw an error', () => {
|
||||
expect(() =>
|
||||
getBuilder().setIntegrationTypes([
|
||||
ApplicationIntegrationType.GuildInstall,
|
||||
ApplicationIntegrationType.UserInstall,
|
||||
]),
|
||||
).not.toThrowError();
|
||||
|
||||
expect(() =>
|
||||
getBuilder().setIntegrationTypes(
|
||||
ApplicationIntegrationType.GuildInstall,
|
||||
ApplicationIntegrationType.UserInstall,
|
||||
),
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN a builder with invalid integration types THEN does throw an error', () => {
|
||||
// @ts-expect-error: Invalid integration types
|
||||
expect(() => getBuilder().setIntegrationTypes(999)).toThrowError();
|
||||
|
||||
// @ts-expect-error: Invalid integration types
|
||||
expect(() => getBuilder().setIntegrationTypes([999, 998])).toThrowError();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { ChannelType, PermissionFlagsBits, type APIApplicationCommandOptionChoice } from 'discord-api-types/v10';
|
||||
import {
|
||||
ApplicationIntegrationType,
|
||||
ChannelType,
|
||||
InteractionContextType,
|
||||
PermissionFlagsBits,
|
||||
type APIApplicationCommandOptionChoice,
|
||||
} from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
SlashCommandAssertions,
|
||||
@@ -532,5 +538,51 @@ describe('Slash Commands', () => {
|
||||
expect(() => getBuilder().addChannelOption(getChannelOption()).setDMPermission(false)).not.toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('contexts', () => {
|
||||
test('GIVEN a builder with valid contexts THEN does not throw an error', () => {
|
||||
expect(() =>
|
||||
getBuilder().setContexts([InteractionContextType.Guild, InteractionContextType.BotDM]),
|
||||
).not.toThrowError();
|
||||
|
||||
expect(() =>
|
||||
getBuilder().setContexts(InteractionContextType.Guild, InteractionContextType.BotDM),
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN a builder with invalid contexts THEN does throw an error', () => {
|
||||
// @ts-expect-error: Invalid contexts
|
||||
expect(() => getBuilder().setContexts(999)).toThrowError();
|
||||
|
||||
// @ts-expect-error: Invalid contexts
|
||||
expect(() => getBuilder().setContexts([999, 998])).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('integration types', () => {
|
||||
test('GIVEN a builder with valid integraton types THEN does not throw an error', () => {
|
||||
expect(() =>
|
||||
getBuilder().setIntegrationTypes([
|
||||
ApplicationIntegrationType.GuildInstall,
|
||||
ApplicationIntegrationType.UserInstall,
|
||||
]),
|
||||
).not.toThrowError();
|
||||
|
||||
expect(() =>
|
||||
getBuilder().setIntegrationTypes(
|
||||
ApplicationIntegrationType.GuildInstall,
|
||||
ApplicationIntegrationType.UserInstall,
|
||||
),
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN a builder with invalid integration types THEN does throw an error', () => {
|
||||
// @ts-expect-error: Invalid integration types
|
||||
expect(() => getBuilder().setIntegrationTypes(999)).toThrowError();
|
||||
|
||||
// @ts-expect-error: Invalid integration types
|
||||
expect(() => getBuilder().setIntegrationTypes([999, 998])).toThrowError();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
"@discordjs/formatters": "workspace:^",
|
||||
"@discordjs/util": "workspace:^",
|
||||
"@sapphire/shapeshift": "^3.9.7",
|
||||
"discord-api-types": "0.37.83",
|
||||
"discord-api-types": "^0.37.114",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"ts-mixer": "^6.0.4",
|
||||
"tslib": "^2.6.2"
|
||||
@@ -76,19 +76,19 @@
|
||||
"devDependencies": {
|
||||
"@discordjs/api-extractor": "workspace:^",
|
||||
"@discordjs/scripts": "workspace:^",
|
||||
"@favware/cliff-jumper": "^3.0.2",
|
||||
"@favware/cliff-jumper": "^3.0.3",
|
||||
"@types/node": "16.18.60",
|
||||
"@vitest/coverage-v8": "^1.5.0",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"esbuild-plugin-version-injector": "^1.2.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"prettier": "^3.2.5",
|
||||
"tsup": "^8.0.2",
|
||||
"turbo": "^1.13.2",
|
||||
"prettier": "^3.3.0",
|
||||
"tsup": "^8.1.0",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5",
|
||||
"vitest": "^1.5.0"
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.11.0"
|
||||
|
||||
@@ -81,21 +81,36 @@ export function validateRequiredButtonParameters(
|
||||
label?: string,
|
||||
emoji?: APIMessageComponentEmoji,
|
||||
customId?: string,
|
||||
skuId?: string,
|
||||
url?: string,
|
||||
) {
|
||||
if (url && customId) {
|
||||
throw new RangeError('URL and custom id are mutually exclusive');
|
||||
}
|
||||
|
||||
if (!label && !emoji) {
|
||||
throw new RangeError('Buttons must have a label and/or an emoji');
|
||||
}
|
||||
|
||||
if (style === ButtonStyle.Link) {
|
||||
if (!url) {
|
||||
throw new RangeError('Link buttons must have a url');
|
||||
if (style === ButtonStyle.Premium) {
|
||||
if (!skuId) {
|
||||
throw new RangeError('Premium buttons must have an SKU id.');
|
||||
}
|
||||
|
||||
if (customId || label || url || emoji) {
|
||||
throw new RangeError('Premium buttons cannot have a custom id, label, URL, or emoji.');
|
||||
}
|
||||
} else {
|
||||
if (skuId) {
|
||||
throw new RangeError('Non-premium buttons must not have an SKU id.');
|
||||
}
|
||||
|
||||
if (url && customId) {
|
||||
throw new RangeError('URL and custom id are mutually exclusive.');
|
||||
}
|
||||
|
||||
if (!label && !emoji) {
|
||||
throw new RangeError('Non-premium buttons must have a label and/or an emoji.');
|
||||
}
|
||||
|
||||
if (style === ButtonStyle.Link) {
|
||||
if (!url) {
|
||||
throw new RangeError('Link buttons must have a URL.');
|
||||
}
|
||||
} else if (url) {
|
||||
throw new RangeError('Non-premium and non-link buttons cannot have a URL.');
|
||||
}
|
||||
} else if (url) {
|
||||
throw new RangeError('Non-link buttons cannot have a url');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import {
|
||||
ComponentType,
|
||||
type APIMessageComponentEmoji,
|
||||
type APIButtonComponent,
|
||||
type APIButtonComponentWithURL,
|
||||
type APIButtonComponentWithCustomId,
|
||||
type APIButtonComponentWithSKUId,
|
||||
type APIButtonComponentWithURL,
|
||||
type APIMessageComponentEmoji,
|
||||
type ButtonStyle,
|
||||
type Snowflake,
|
||||
} from 'discord-api-types/v10';
|
||||
import {
|
||||
buttonLabelValidator,
|
||||
@@ -88,13 +90,24 @@ export class ButtonBuilder extends ComponentBuilder<APIButtonComponent> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SKU id that represents a purchasable SKU for this button.
|
||||
*
|
||||
* @remarks Only available when using premium-style buttons.
|
||||
* @param skuId - The SKU id to use
|
||||
*/
|
||||
public setSKUId(skuId: Snowflake) {
|
||||
(this.data as APIButtonComponentWithSKUId).sku_id = skuId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the emoji to display on this button.
|
||||
*
|
||||
* @param emoji - The emoji to use
|
||||
*/
|
||||
public setEmoji(emoji: APIMessageComponentEmoji) {
|
||||
this.data.emoji = emojiValidator.parse(emoji);
|
||||
(this.data as Exclude<APIButtonComponent, APIButtonComponentWithSKUId>).emoji = emojiValidator.parse(emoji);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -114,7 +127,7 @@ export class ButtonBuilder extends ComponentBuilder<APIButtonComponent> {
|
||||
* @param label - The label to use
|
||||
*/
|
||||
public setLabel(label: string) {
|
||||
this.data.label = buttonLabelValidator.parse(label);
|
||||
(this.data as Exclude<APIButtonComponent, APIButtonComponentWithSKUId>).label = buttonLabelValidator.parse(label);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -124,9 +137,10 @@ export class ButtonBuilder extends ComponentBuilder<APIButtonComponent> {
|
||||
public toJSON(): APIButtonComponent {
|
||||
validateRequiredButtonParameters(
|
||||
this.data.style,
|
||||
this.data.label,
|
||||
this.data.emoji,
|
||||
(this.data as Exclude<APIButtonComponent, APIButtonComponentWithSKUId>).label,
|
||||
(this.data as Exclude<APIButtonComponent, APIButtonComponentWithSKUId>).emoji,
|
||||
(this.data as APIButtonComponentWithCustomId).custom_id,
|
||||
(this.data as APIButtonComponentWithSKUId).sku_id,
|
||||
(this.data as APIButtonComponentWithURL).url,
|
||||
);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { s } from '@sapphire/shapeshift';
|
||||
import { ApplicationCommandType } from 'discord-api-types/v10';
|
||||
import { ApplicationCommandType, ApplicationIntegrationType, InteractionContextType } from 'discord-api-types/v10';
|
||||
import { isValidationEnabled } from '../../util/validation.js';
|
||||
import type { ContextMenuCommandType } from './ContextMenuCommandBuilder.js';
|
||||
|
||||
@@ -49,3 +49,11 @@ const memberPermissionPredicate = s.union(
|
||||
export function validateDefaultMemberPermissions(permissions: unknown) {
|
||||
return memberPermissionPredicate.parse(permissions);
|
||||
}
|
||||
|
||||
export const contextsPredicate = s.array(
|
||||
s.nativeEnum(InteractionContextType).setValidationEnabled(isValidationEnabled),
|
||||
);
|
||||
|
||||
export const integrationTypesPredicate = s.array(
|
||||
s.nativeEnum(ApplicationIntegrationType).setValidationEnabled(isValidationEnabled),
|
||||
);
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import type {
|
||||
ApplicationCommandType,
|
||||
ApplicationIntegrationType,
|
||||
InteractionContextType,
|
||||
LocaleString,
|
||||
LocalizationMap,
|
||||
Permissions,
|
||||
RESTPostAPIContextMenuApplicationCommandsJSONBody,
|
||||
} from 'discord-api-types/v10';
|
||||
import type { RestOrArray } from '../../util/normalizeArray.js';
|
||||
import { normalizeArray } from '../../util/normalizeArray.js';
|
||||
import { validateLocale, validateLocalizationMap } from '../slashCommands/Assertions.js';
|
||||
import {
|
||||
validateRequiredParameters,
|
||||
@@ -13,6 +17,8 @@ import {
|
||||
validateDefaultPermission,
|
||||
validateDefaultMemberPermissions,
|
||||
validateDMPermission,
|
||||
contextsPredicate,
|
||||
integrationTypesPredicate,
|
||||
} from './Assertions.js';
|
||||
|
||||
/**
|
||||
@@ -39,6 +45,11 @@ export class ContextMenuCommandBuilder {
|
||||
*/
|
||||
public readonly type: ContextMenuCommandType = undefined!;
|
||||
|
||||
/**
|
||||
* The contexts for this command.
|
||||
*/
|
||||
public readonly contexts?: InteractionContextType[];
|
||||
|
||||
/**
|
||||
* Whether this command is enabled by default when the application is added to a guild.
|
||||
*
|
||||
@@ -59,6 +70,33 @@ export class ContextMenuCommandBuilder {
|
||||
*/
|
||||
public readonly dm_permission: boolean | undefined = undefined;
|
||||
|
||||
/**
|
||||
* The integration types for this command.
|
||||
*/
|
||||
public readonly integration_types?: ApplicationIntegrationType[];
|
||||
|
||||
/**
|
||||
* Sets the contexts of this command.
|
||||
*
|
||||
* @param contexts - The contexts
|
||||
*/
|
||||
public setContexts(...contexts: RestOrArray<InteractionContextType>) {
|
||||
Reflect.set(this, 'contexts', contextsPredicate.parse(normalizeArray(contexts)));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets integration types of this command.
|
||||
*
|
||||
* @param integrationTypes - The integration types
|
||||
*/
|
||||
public setIntegrationTypes(...integrationTypes: RestOrArray<ApplicationIntegrationType>) {
|
||||
Reflect.set(this, 'integration_types', integrationTypesPredicate.parse(normalizeArray(integrationTypes)));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of this command.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { s } from '@sapphire/shapeshift';
|
||||
import { Locale, type APIApplicationCommandOptionChoice, type LocalizationMap } from 'discord-api-types/v10';
|
||||
import {
|
||||
ApplicationIntegrationType,
|
||||
InteractionContextType,
|
||||
Locale,
|
||||
type APIApplicationCommandOptionChoice,
|
||||
type LocalizationMap,
|
||||
} from 'discord-api-types/v10';
|
||||
import { isValidationEnabled } from '../../util/validation.js';
|
||||
import type { ToAPIApplicationCommandOptions } from './SlashCommandBuilder.js';
|
||||
import type { SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder } from './SlashCommandSubcommands.js';
|
||||
@@ -98,3 +104,11 @@ export function validateDefaultMemberPermissions(permissions: unknown) {
|
||||
export function validateNSFW(value: unknown): asserts value is boolean {
|
||||
booleanPredicate.parse(value);
|
||||
}
|
||||
|
||||
export const contextsPredicate = s.array(
|
||||
s.nativeEnum(InteractionContextType).setValidationEnabled(isValidationEnabled),
|
||||
);
|
||||
|
||||
export const integrationTypesPredicate = s.array(
|
||||
s.nativeEnum(ApplicationIntegrationType).setValidationEnabled(isValidationEnabled),
|
||||
);
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import type { APIApplicationCommandOption, LocalizationMap, Permissions } from 'discord-api-types/v10';
|
||||
import type {
|
||||
APIApplicationCommandOption,
|
||||
ApplicationIntegrationType,
|
||||
InteractionContextType,
|
||||
LocalizationMap,
|
||||
Permissions,
|
||||
} from 'discord-api-types/v10';
|
||||
import { mix } from 'ts-mixer';
|
||||
import { SharedNameAndDescription } from './mixins/NameAndDescription.js';
|
||||
import { SharedSlashCommand } from './mixins/SharedSlashCommand.js';
|
||||
@@ -35,6 +41,11 @@ export class SlashCommandBuilder {
|
||||
*/
|
||||
public readonly options: ToAPIApplicationCommandOptions[] = [];
|
||||
|
||||
/**
|
||||
* The contexts for this command.
|
||||
*/
|
||||
public readonly contexts?: InteractionContextType[];
|
||||
|
||||
/**
|
||||
* Whether this command is enabled by default when the application is added to a guild.
|
||||
*
|
||||
@@ -55,6 +66,11 @@ export class SlashCommandBuilder {
|
||||
*/
|
||||
public readonly dm_permission: boolean | undefined = undefined;
|
||||
|
||||
/**
|
||||
* The integration types for this command.
|
||||
*/
|
||||
public readonly integration_types?: ApplicationIntegrationType[];
|
||||
|
||||
/**
|
||||
* Whether this command is NSFW.
|
||||
*/
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
import type {
|
||||
ApplicationIntegrationType,
|
||||
InteractionContextType,
|
||||
LocalizationMap,
|
||||
Permissions,
|
||||
RESTPostAPIChatInputApplicationCommandsJSONBody,
|
||||
} from 'discord-api-types/v10';
|
||||
import type { RestOrArray } from '../../../util/normalizeArray.js';
|
||||
import { normalizeArray } from '../../../util/normalizeArray.js';
|
||||
import {
|
||||
contextsPredicate,
|
||||
integrationTypesPredicate,
|
||||
validateDMPermission,
|
||||
validateDefaultMemberPermissions,
|
||||
validateDefaultPermission,
|
||||
@@ -27,6 +33,8 @@ export class SharedSlashCommand {
|
||||
|
||||
public readonly options: ToAPIApplicationCommandOptions[] = [];
|
||||
|
||||
public readonly contexts?: InteractionContextType[];
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link SharedSlashCommand.setDefaultMemberPermissions} or {@link SharedSlashCommand.setDMPermission} instead.
|
||||
*/
|
||||
@@ -36,8 +44,32 @@ export class SharedSlashCommand {
|
||||
|
||||
public readonly dm_permission: boolean | undefined = undefined;
|
||||
|
||||
public readonly integration_types?: ApplicationIntegrationType[];
|
||||
|
||||
public readonly nsfw: boolean | undefined = undefined;
|
||||
|
||||
/**
|
||||
* Sets the contexts of this command.
|
||||
*
|
||||
* @param contexts - The contexts
|
||||
*/
|
||||
public setContexts(...contexts: RestOrArray<InteractionContextType>) {
|
||||
Reflect.set(this, 'contexts', contextsPredicate.parse(normalizeArray(contexts)));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the integration types of this command.
|
||||
*
|
||||
* @param integrationTypes - The integration types
|
||||
*/
|
||||
public setIntegrationTypes(...integrationTypes: RestOrArray<ApplicationIntegrationType>) {
|
||||
Reflect.set(this, 'integration_types', integrationTypesPredicate.parse(normalizeArray(integrationTypes)));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the command is enabled by default when the application is added to a guild.
|
||||
*
|
||||
|
||||
@@ -138,6 +138,12 @@ describe('each() tests', () => {
|
||||
expectInvalidFunctionError(() => coll.each(123), 123);
|
||||
});
|
||||
|
||||
test('binds the thisArg', () => {
|
||||
coll.each(function each() {
|
||||
expect(this).toBeNull();
|
||||
}, null);
|
||||
});
|
||||
|
||||
test('iterate over each item', () => {
|
||||
const coll = createTestCollection();
|
||||
const a: [string, number][] = [];
|
||||
@@ -964,6 +970,10 @@ describe('findLast() tests', () => {
|
||||
expect(coll.findLast((value) => value % 2 === 1)).toStrictEqual(3);
|
||||
});
|
||||
|
||||
test('returns undefined if no item matches', () => {
|
||||
expect(coll.findLast((value) => value === 10)).toBeUndefined();
|
||||
});
|
||||
|
||||
test('throws if fn is not a function', () => {
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => createCollection().findLast());
|
||||
@@ -985,6 +995,10 @@ describe('findLastKey() tests', () => {
|
||||
expect(coll.findLastKey((value) => value % 2 === 1)).toStrictEqual('c');
|
||||
});
|
||||
|
||||
test('returns undefined if no item matches', () => {
|
||||
expect(coll.findLastKey((value) => value === 10)).toBeUndefined();
|
||||
});
|
||||
|
||||
test('throws if fn is not a function', () => {
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => createCollection().findLastKey());
|
||||
|
||||
@@ -63,19 +63,19 @@
|
||||
"devDependencies": {
|
||||
"@discordjs/api-extractor": "workspace:^",
|
||||
"@discordjs/scripts": "workspace:^",
|
||||
"@favware/cliff-jumper": "^3.0.2",
|
||||
"@favware/cliff-jumper": "^3.0.3",
|
||||
"@types/node": "18.18.8",
|
||||
"@vitest/coverage-v8": "^1.5.0",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"esbuild-plugin-version-injector": "^1.2.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"prettier": "^3.2.5",
|
||||
"tsup": "^8.0.2",
|
||||
"turbo": "^1.13.2",
|
||||
"prettier": "^3.3.0",
|
||||
"tsup": "^8.1.0",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5",
|
||||
"vitest": "^1.5.0"
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
||||
@@ -70,24 +70,24 @@
|
||||
"@discordjs/ws": "workspace:^",
|
||||
"@sapphire/snowflake": "^3.5.3",
|
||||
"@vladfrangu/async_event_emitter": "^2.2.4",
|
||||
"discord-api-types": "0.37.83"
|
||||
"discord-api-types": "^0.37.114"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@discordjs/api-extractor": "workspace:^",
|
||||
"@discordjs/scripts": "workspace:^",
|
||||
"@favware/cliff-jumper": "^3.0.2",
|
||||
"@favware/cliff-jumper": "^3.0.3",
|
||||
"@types/node": "18.18.8",
|
||||
"@vitest/coverage-v8": "^1.5.0",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"esbuild-plugin-version-injector": "^1.2.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"prettier": "^3.2.5",
|
||||
"tsup": "^8.0.2",
|
||||
"turbo": "^1.13.2",
|
||||
"prettier": "^3.3.0",
|
||||
"tsup": "^8.1.0",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5",
|
||||
"vitest": "^1.5.0"
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
||||
@@ -258,6 +258,7 @@ export class InteractionsAPI {
|
||||
* @param interactionId - The id of the interaction
|
||||
* @param interactionToken - The token of the interaction
|
||||
* @param options - The options for sending the premium required response
|
||||
* @deprecated Sending a premium-style button is the new Discord behaviour.
|
||||
*/
|
||||
public async sendPremiumRequired(
|
||||
interactionId: Snowflake,
|
||||
|
||||
@@ -17,7 +17,7 @@ export class StageInstancesAPI {
|
||||
/**
|
||||
* Creates a new stage instance
|
||||
*
|
||||
* @see {@link https://discord.com/developers/docs/resources/stage-instance#get-stage-instance}
|
||||
* @see {@link https://discord.com/developers/docs/resources/stage-instance#create-stage-instance}
|
||||
* @param body - The data for creating the new stage instance
|
||||
* @param options - The options for creating the new stage instance
|
||||
*/
|
||||
|
||||
@@ -201,8 +201,8 @@ export class Client extends AsyncEventEmitter<MappedEvents> {
|
||||
|
||||
this.gateway.on(WebSocketShardEvents.Dispatch, ({ data: dispatch, shardId }) => {
|
||||
this.emit(
|
||||
// @ts-expect-error ws/1.1.
|
||||
dispatch.t,
|
||||
// @ts-expect-error event props can't be resolved properly, but they are correct
|
||||
this.wrapIntrinsicProps(dispatch.d, shardId),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -49,28 +49,28 @@
|
||||
"homepage": "https://discord.js.org",
|
||||
"funding": "https://github.com/discordjs/discord.js?sponsor",
|
||||
"dependencies": {
|
||||
"commander": "^12.0.0",
|
||||
"commander": "^12.1.0",
|
||||
"fast-glob": "^3.3.2",
|
||||
"picocolors": "^1.0.0",
|
||||
"picocolors": "^1.0.1",
|
||||
"prompts": "^2.4.2",
|
||||
"validate-npm-package-name": "^5.0.0"
|
||||
"validate-npm-package-name": "^5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@discordjs/api-extractor": "workspace:^",
|
||||
"@favware/cliff-jumper": "^3.0.2",
|
||||
"@favware/cliff-jumper": "^3.0.3",
|
||||
"@types/node": "18.18.8",
|
||||
"@types/prompts": "^2.4.9",
|
||||
"@types/validate-npm-package-name": "^4.0.2",
|
||||
"@vitest/coverage-v8": "^1.5.0",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"prettier": "^3.2.5",
|
||||
"terser": "^5.29.1",
|
||||
"tsup": "^8.0.2",
|
||||
"prettier": "^3.3.0",
|
||||
"terser": "^5.31.0",
|
||||
"tsup": "^8.1.0",
|
||||
"typescript": "^5.4.5",
|
||||
"vitest": "^1.5.0"
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
||||
@@ -72,11 +72,11 @@
|
||||
"@discordjs/util": "workspace:^",
|
||||
"@discordjs/ws": "workspace:^",
|
||||
"@sapphire/snowflake": "3.5.3",
|
||||
"discord-api-types": "0.37.83",
|
||||
"discord-api-types": "^0.37.114",
|
||||
"fast-deep-equal": "3.1.3",
|
||||
"lodash.snakecase": "4.1.1",
|
||||
"tslib": "2.6.2",
|
||||
"undici": "6.13.0"
|
||||
"undici": "6.18.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@discordjs/api-extractor": "workspace:^",
|
||||
@@ -84,17 +84,17 @@
|
||||
"@discordjs/scripts": "workspace:^",
|
||||
"@favware/cliff-jumper": "3.0.2",
|
||||
"@types/node": "16.18.60",
|
||||
"@typescript-eslint/eslint-plugin": "^7.7.0",
|
||||
"@typescript-eslint/parser": "^7.7.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.11.0",
|
||||
"@typescript-eslint/parser": "^7.11.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"dtslint": "4.2.1",
|
||||
"eslint": "8.57.0",
|
||||
"eslint-formatter-pretty": "5.0.0",
|
||||
"jest": "29.7.0",
|
||||
"prettier": "3.2.5",
|
||||
"tsd": "0.30.7",
|
||||
"tsd": "0.31.0",
|
||||
"tslint": "6.1.3",
|
||||
"turbo": "^1.13.2",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "5.4.5"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -117,14 +117,14 @@ class WebSocketManager extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Emits a debug message.
|
||||
* @param {string} message The debug message
|
||||
* @param {string[]} messages The debug message
|
||||
* @param {?number} [shardId] The id of the shard that emitted this message, if any
|
||||
* @private
|
||||
*/
|
||||
debug(message, shardId) {
|
||||
debug(messages, shardId) {
|
||||
this.client.emit(
|
||||
Events.Debug,
|
||||
`[WS => ${typeof shardId === 'number' ? `Shard ${shardId}` : 'Manager'}] ${message}`,
|
||||
`[WS => ${typeof shardId === 'number' ? `Shard ${shardId}` : 'Manager'}] ${messages.join('\n\t')}`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -170,15 +170,8 @@ class WebSocketManager extends EventEmitter {
|
||||
});
|
||||
|
||||
const { total, remaining } = sessionStartLimit;
|
||||
|
||||
this.debug(`Fetched Gateway Information
|
||||
URL: ${gatewayURL}
|
||||
Recommended Shards: ${recommendedShards}`);
|
||||
|
||||
this.debug(`Session Limit Information
|
||||
Total: ${total}
|
||||
Remaining: ${remaining}`);
|
||||
|
||||
this.debug(['Fetched Gateway Information', `URL: ${gatewayURL}`, `Recommended Shards: ${recommendedShards}`]);
|
||||
this.debug(['Session Limit Information', `Total: ${total}`, `Remaining: ${remaining}`]);
|
||||
this.gateway = `${gatewayURL}/`;
|
||||
|
||||
this.client.options.shardCount = await this._ws.getShardCount();
|
||||
@@ -231,7 +224,7 @@ class WebSocketManager extends EventEmitter {
|
||||
* @private
|
||||
*/
|
||||
attachEvents() {
|
||||
this._ws.on(WSWebSocketShardEvents.Debug, ({ message, shardId }) => this.debug(message, shardId));
|
||||
this._ws.on(WSWebSocketShardEvents.Debug, ({ message, shardId }) => this.debug([message], shardId));
|
||||
this._ws.on(WSWebSocketShardEvents.Dispatch, ({ data, shardId }) => {
|
||||
this.client.emit(Events.Raw, data, shardId);
|
||||
this.emit(data.t, data.d, shardId);
|
||||
@@ -258,7 +251,7 @@ class WebSocketManager extends EventEmitter {
|
||||
* @param {number} id The shard id that disconnected
|
||||
*/
|
||||
this.client.emit(Events.ShardDisconnect, { code, reason: reasonIsDeprecated, wasClean: true }, shardId);
|
||||
this.debug(`Shard not resumable: ${code} (${GatewayCloseCodes[code] ?? CloseCodes[code]})`, shardId);
|
||||
this.debug([`Shard not resumable: ${code} (${GatewayCloseCodes[code] ?? CloseCodes[code]})`], shardId);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -291,7 +284,7 @@ class WebSocketManager extends EventEmitter {
|
||||
});
|
||||
|
||||
this._ws.on(WSWebSocketShardEvents.HeartbeatComplete, ({ heartbeatAt, latency, shardId }) => {
|
||||
this.debug(`Heartbeat acknowledged, latency of ${latency}ms.`, shardId);
|
||||
this.debug([`Heartbeat acknowledged, latency of ${latency}ms.`], shardId);
|
||||
const shard = this.shards.get(shardId);
|
||||
shard.lastPingTimestamp = heartbeatAt;
|
||||
shard.ping = latency;
|
||||
@@ -324,7 +317,7 @@ class WebSocketManager extends EventEmitter {
|
||||
async destroy() {
|
||||
if (this.destroyed) return;
|
||||
// TODO: Make a util for getting a stack
|
||||
this.debug(Object.assign(new Error(), { name: 'Manager was destroyed:' }).stack);
|
||||
this.debug([Object.assign(new Error(), { name: 'Manager was destroyed:' }).stack]);
|
||||
this.destroyed = true;
|
||||
await this._ws?.destroy({ code: CloseCodes.Normal, reason: 'Manager was destroyed' });
|
||||
}
|
||||
|
||||
@@ -85,11 +85,11 @@ class WebSocketShard extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Emits a debug event.
|
||||
* @param {string} message The debug message
|
||||
* @param {string[]} messages The debug message
|
||||
* @private
|
||||
*/
|
||||
debug(message) {
|
||||
this.manager.debug(message, this.id);
|
||||
debug(messages) {
|
||||
this.manager.debug(messages, this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,10 +110,13 @@ class WebSocketShard extends EventEmitter {
|
||||
wasClean: false,
|
||||
},
|
||||
) {
|
||||
this.debug(`[CLOSE]
|
||||
Event Code: ${event.code}
|
||||
Clean : ${event.wasClean}
|
||||
Reason : ${event.reason ?? 'No reason received'}`);
|
||||
this.debug([
|
||||
'[CLOSE]',
|
||||
`Event Code: ${event.code}`,
|
||||
`Clean : ${event.wasClean}`,
|
||||
`Reason : ${event.reason ?? 'No reason received'}`,
|
||||
]);
|
||||
|
||||
/**
|
||||
* Emitted when a shard's WebSocket closes.
|
||||
* @private
|
||||
@@ -130,7 +133,7 @@ class WebSocketShard extends EventEmitter {
|
||||
*/
|
||||
onReadyPacket(packet) {
|
||||
if (!packet) {
|
||||
this.debug(`Received broken packet: '${packet}'.`);
|
||||
this.debug([`Received broken packet: '${packet}'.`]);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -167,7 +170,7 @@ class WebSocketShard extends EventEmitter {
|
||||
}
|
||||
// Step 1. If we don't have any other guilds pending, we are ready
|
||||
if (!this.expectedGuilds.size) {
|
||||
this.debug('Shard received all its guilds. Marking as fully ready.');
|
||||
this.debug(['Shard received all its guilds. Marking as fully ready.']);
|
||||
this.status = Status.Ready;
|
||||
|
||||
/**
|
||||
@@ -191,12 +194,12 @@ class WebSocketShard extends EventEmitter {
|
||||
|
||||
this.readyTimeout = setTimeout(
|
||||
() => {
|
||||
this.debug(
|
||||
`Shard ${hasGuildsIntent ? 'did' : 'will'} not receive any more guild packets` +
|
||||
`${hasGuildsIntent ? ` in ${waitGuildTimeout} ms` : ''}.\nUnavailable guild count: ${
|
||||
this.expectedGuilds.size
|
||||
}`,
|
||||
);
|
||||
this.debug([
|
||||
hasGuildsIntent
|
||||
? `Shard did not receive any guild packets in ${waitGuildTimeout} ms.`
|
||||
: 'Shard will not receive anymore guild packets.',
|
||||
`Unavailable guild count: ${this.expectedGuilds.size}`,
|
||||
]);
|
||||
|
||||
this.readyTimeout = null;
|
||||
this.status = Status.Ready;
|
||||
|
||||
@@ -57,7 +57,9 @@ class AutoModerationRuleManager extends CachedManager {
|
||||
* @property {AutoModerationRuleKeywordPresetType[]} [presets]
|
||||
* The internally pre-defined wordsets which will be searched for in the content
|
||||
* @property {string[]} [allowList] The substrings that will be exempt from triggering
|
||||
* {@link AutoModerationRuleTriggerType.Keyword} and {@link AutoModerationRuleTriggerType.KeywordPreset}
|
||||
* {@link AutoModerationRuleTriggerType.Keyword},
|
||||
* {@link AutoModerationRuleTriggerType.KeywordPreset},
|
||||
* and {@link AutoModerationRuleTriggerType.MemberProfile}
|
||||
* @property {?number} [mentionTotalLimit] The total number of role & user mentions allowed per message
|
||||
* @property {boolean} [mentionRaidProtectionEnabled] Whether to automatically detect mention raids
|
||||
*/
|
||||
@@ -87,8 +89,10 @@ class AutoModerationRuleManager extends CachedManager {
|
||||
* @property {AutoModerationRuleTriggerType} triggerType The trigger type of the auto moderation rule
|
||||
* @property {AutoModerationTriggerMetadataOptions} [triggerMetadata] The trigger metadata of the auto moderation rule
|
||||
* <info>This property is required if using a `triggerType` of
|
||||
* {@link AutoModerationRuleTriggerType.Keyword}, {@link AutoModerationRuleTriggerType.KeywordPreset},
|
||||
* or {@link AutoModerationRuleTriggerType.MentionSpam}.</info>
|
||||
* {@link AutoModerationRuleTriggerType.Keyword},
|
||||
* {@link AutoModerationRuleTriggerType.KeywordPreset},
|
||||
* {@link AutoModerationRuleTriggerType.MentionSpam},
|
||||
* or {@link AutoModerationRuleTriggerType.MemberProfile}.</info>
|
||||
* @property {AutoModerationActionOptions[]} actions
|
||||
* The actions that will execute when the auto moderation rule is triggered
|
||||
* @property {boolean} [enabled] Whether the auto moderation rule should be enabled
|
||||
|
||||
@@ -284,13 +284,13 @@ class GuildChannelManager extends CachedManager {
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async edit(channel, options) {
|
||||
channel = this.resolve(channel);
|
||||
if (!channel) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable');
|
||||
const resolvedChannel = this.resolve(channel);
|
||||
if (!resolvedChannel) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable');
|
||||
|
||||
const parent = options.parent && this.client.channels.resolveId(options.parent);
|
||||
|
||||
if (options.position !== undefined) {
|
||||
await this.setPosition(channel, options.position, { position: options.position, reason: options.reason });
|
||||
await this.setPosition(resolvedChannel, options.position, { position: options.position, reason: options.reason });
|
||||
}
|
||||
|
||||
let permission_overwrites = options.permissionOverwrites?.map(overwrite =>
|
||||
@@ -305,22 +305,22 @@ class GuildChannelManager extends CachedManager {
|
||||
PermissionOverwrites.resolve(overwrite, this.guild),
|
||||
);
|
||||
}
|
||||
} else if (channel.parent) {
|
||||
permission_overwrites = channel.parent.permissionOverwrites.cache.map(overwrite =>
|
||||
} else if (resolvedChannel.parent) {
|
||||
permission_overwrites = resolvedChannel.parent.permissionOverwrites.cache.map(overwrite =>
|
||||
PermissionOverwrites.resolve(overwrite, this.guild),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const newData = await this.client.rest.patch(Routes.channel(channel.id), {
|
||||
const newData = await this.client.rest.patch(Routes.channel(resolvedChannel.id), {
|
||||
body: {
|
||||
name: (options.name ?? channel.name).trim(),
|
||||
name: options.name,
|
||||
type: options.type,
|
||||
topic: options.topic,
|
||||
nsfw: options.nsfw,
|
||||
bitrate: options.bitrate ?? channel.bitrate,
|
||||
user_limit: options.userLimit ?? channel.userLimit,
|
||||
rtc_region: 'rtcRegion' in options ? options.rtcRegion : channel.rtcRegion,
|
||||
bitrate: options.bitrate,
|
||||
user_limit: options.userLimit,
|
||||
rtc_region: options.rtcRegion,
|
||||
video_quality_mode: options.videoQualityMode,
|
||||
parent_id: parent,
|
||||
lock_permissions: options.lockPermissions,
|
||||
|
||||
@@ -128,8 +128,9 @@ class GuildMemberManager extends CachedManager {
|
||||
resolvedOptions.roles = resolvedRoles;
|
||||
}
|
||||
const data = await this.client.rest.put(Routes.guildMember(this.guild.id, userId), { body: resolvedOptions });
|
||||
// Data is an empty Uint8Array if the member is already part of the guild.
|
||||
return data instanceof Uint8Array
|
||||
|
||||
// Data is an empty array buffer if the member is already part of the guild.
|
||||
return data instanceof ArrayBuffer
|
||||
? options.fetchWhenExisting === false
|
||||
? null
|
||||
: this.fetch(userId)
|
||||
|
||||
@@ -66,7 +66,9 @@ class AutoModerationRule extends Base {
|
||||
* @property {AutoModerationRuleKeywordPresetType[]} presets
|
||||
* The internally pre-defined wordsets which will be searched for in the content
|
||||
* @property {string[]} allowList The substrings that will be exempt from triggering
|
||||
* {@link AutoModerationRuleTriggerType.Keyword} and {@link AutoModerationRuleTriggerType.KeywordPreset}
|
||||
* {@link AutoModerationRuleTriggerType.Keyword},
|
||||
* {@link AutoModerationRuleTriggerType.KeywordPreset},
|
||||
* and {@link AutoModerationRuleTriggerType.MemberProfile}
|
||||
* @property {?number} mentionTotalLimit The total number of role & user mentions allowed per message
|
||||
* @property {boolean} mentionRaidProtectionEnabled Whether mention raid protection is enabled
|
||||
*/
|
||||
@@ -209,7 +211,9 @@ class AutoModerationRule extends Base {
|
||||
/**
|
||||
* Sets the allow list for this auto moderation rule.
|
||||
* @param {string[]} allowList The substrings that will be exempt from triggering
|
||||
* {@link AutoModerationRuleTriggerType.Keyword} and {@link AutoModerationRuleTriggerType.KeywordPreset}
|
||||
* {@link AutoModerationRuleTriggerType.Keyword},
|
||||
* {@link AutoModerationRuleTriggerType.KeywordPreset},
|
||||
* and {@link AutoModerationRuleTriggerType.MemberProfile}
|
||||
* @param {string} [reason] The reason for changing the allow list of this auto moderation rule
|
||||
* @returns {Promise<AutoModerationRule>}
|
||||
*/
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
const { DiscordSnowflake } = require('@sapphire/snowflake');
|
||||
const { AuditLogOptionsType, AuditLogEvent } = require('discord-api-types/v10');
|
||||
const AutoModerationRule = require('./AutoModerationRule');
|
||||
const { GuildOnboardingPrompt } = require('./GuildOnboardingPrompt');
|
||||
const { GuildScheduledEvent } = require('./GuildScheduledEvent');
|
||||
const Integration = require('./Integration');
|
||||
const Invite = require('./Invite');
|
||||
@@ -29,6 +30,8 @@ const Targets = {
|
||||
Thread: 'Thread',
|
||||
ApplicationCommand: 'ApplicationCommand',
|
||||
AutoModeration: 'AutoModeration',
|
||||
GuildOnboarding: 'GuildOnboarding',
|
||||
GuildOnboardingPrompt: 'GuildOnboardingPrompt',
|
||||
Unknown: 'Unknown',
|
||||
};
|
||||
|
||||
@@ -49,10 +52,11 @@ const Targets = {
|
||||
* * A thread
|
||||
* * An application command
|
||||
* * An auto moderation rule
|
||||
* * A guild onboarding prompt
|
||||
* * An object with an id key if target was deleted or fake entity
|
||||
* * An object where the keys represent either the new value or the old value
|
||||
* @typedef {?(Object|Guild|BaseChannel|User|Role|Invite|Webhook|GuildEmoji|Message|Integration|StageInstance|Sticker|
|
||||
* GuildScheduledEvent|ApplicationCommand|AutoModerationRule)} AuditLogEntryTarget
|
||||
* GuildScheduledEvent|ApplicationCommand|AutoModerationRule|GuildOnboardingPrompt)} AuditLogEntryTarget
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -80,6 +84,9 @@ const Targets = {
|
||||
* * Thread
|
||||
* * GuildScheduledEvent
|
||||
* * ApplicationCommandPermission
|
||||
* * GuildOnboarding
|
||||
* * GuildOnboardingPrompt
|
||||
* * Unknown
|
||||
* @typedef {string} AuditLogTargetType
|
||||
*/
|
||||
|
||||
@@ -349,6 +356,13 @@ class GuildAuditLogsEntry {
|
||||
changesReduce(this.changes, { id: data.target_id, guild_id: guild.id }),
|
||||
guild,
|
||||
);
|
||||
} else if (targetType === Targets.GuildOnboardingPrompt) {
|
||||
this.target =
|
||||
data.action_type === AuditLogEvent.OnboardingPromptCreate
|
||||
? new GuildOnboardingPrompt(guild.client, changesReduce(this.changes, { id: data.target_id }), guild.id)
|
||||
: changesReduce(this.changes, { id: data.target_id });
|
||||
} else if (targetType === Targets.GuildOnboarding) {
|
||||
this.target = changesReduce(this.changes, { id: data.target_id });
|
||||
} else if (data.target_id) {
|
||||
this.target = guild[`${targetType.toLowerCase()}s`]?.cache.get(data.target_id) ?? { id: data.target_id };
|
||||
}
|
||||
@@ -375,6 +389,8 @@ class GuildAuditLogsEntry {
|
||||
if (target < 120) return Targets.Thread;
|
||||
if (target < 130) return Targets.ApplicationCommand;
|
||||
if (target >= 140 && target < 150) return Targets.AutoModeration;
|
||||
if (target >= 163 && target <= 165) return Targets.GuildOnboardingPrompt;
|
||||
if (target >= 160 && target < 170) return Targets.GuildOnboarding;
|
||||
return Targets.Unknown;
|
||||
}
|
||||
|
||||
@@ -402,6 +418,8 @@ class GuildAuditLogsEntry {
|
||||
AuditLogEvent.ThreadCreate,
|
||||
AuditLogEvent.AutoModerationRuleCreate,
|
||||
AuditLogEvent.AutoModerationBlockMessage,
|
||||
AuditLogEvent.OnboardingPromptCreate,
|
||||
AuditLogEvent.OnboardingCreate,
|
||||
].includes(action)
|
||||
) {
|
||||
return 'Create';
|
||||
@@ -428,6 +446,7 @@ class GuildAuditLogsEntry {
|
||||
AuditLogEvent.GuildScheduledEventDelete,
|
||||
AuditLogEvent.ThreadDelete,
|
||||
AuditLogEvent.AutoModerationRuleDelete,
|
||||
AuditLogEvent.OnboardingPromptDelete,
|
||||
].includes(action)
|
||||
) {
|
||||
return 'Delete';
|
||||
@@ -452,6 +471,8 @@ class GuildAuditLogsEntry {
|
||||
AuditLogEvent.ThreadUpdate,
|
||||
AuditLogEvent.ApplicationCommandPermissionUpdate,
|
||||
AuditLogEvent.AutoModerationRuleUpdate,
|
||||
AuditLogEvent.OnboardingPromptUpdate,
|
||||
AuditLogEvent.OnboardingUpdate,
|
||||
].includes(action)
|
||||
) {
|
||||
return 'Update';
|
||||
|
||||
@@ -417,6 +417,30 @@ class Message extends Base {
|
||||
} else {
|
||||
this.poll ??= null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A call associated with a message
|
||||
* @typedef {Object} MessageCall
|
||||
* @property {Readonly<?Date>} endedAt The time the call ended
|
||||
* @property {?number} endedTimestamp The timestamp the call ended
|
||||
* @property {Snowflake[]} participants The ids of the users that participated in the call
|
||||
*/
|
||||
|
||||
if (data.call) {
|
||||
/**
|
||||
* The call associated with the message
|
||||
* @type {?MessageCall}
|
||||
*/
|
||||
this.call = {
|
||||
endedTimestamp: data.call.ended_timestamp ? Date.parse(data.call.ended_timestamp) : null,
|
||||
participants: data.call.participants,
|
||||
get endedAt() {
|
||||
return this.endedTimestamp && new Date(this.endedTimestamp);
|
||||
},
|
||||
};
|
||||
} else {
|
||||
this.call ??= null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const { deprecate } = require('node:util');
|
||||
const { isJSONEncodable } = require('@discordjs/util');
|
||||
const { InteractionResponseType, MessageFlags, Routes, InteractionType } = require('discord-api-types/v10');
|
||||
const { DiscordjsError, ErrorCodes } = require('../../errors');
|
||||
@@ -266,6 +267,7 @@ class InteractionResponses {
|
||||
/**
|
||||
* Responds to the interaction with an upgrade button.
|
||||
* <info>Only available for applications with monetization enabled.</info>
|
||||
* @deprecated Sending a premium-style button is the new Discord behaviour.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async sendPremiumRequired() {
|
||||
@@ -337,4 +339,10 @@ class InteractionResponses {
|
||||
}
|
||||
}
|
||||
|
||||
InteractionResponses.prototype.sendPremiumRequired = deprecate(
|
||||
InteractionResponses.prototype.sendPremiumRequired,
|
||||
// eslint-disable-next-line max-len
|
||||
'InteractionResponses#sendPremiumRequired() is deprecated. Sending a premium-style button is the new Discord behaviour.',
|
||||
);
|
||||
|
||||
module.exports = InteractionResponses;
|
||||
|
||||
24
packages/discord.js/typings/index.d.ts
vendored
24
packages/discord.js/typings/index.d.ts
vendored
@@ -604,12 +604,14 @@ export abstract class CommandInteraction<Cached extends CacheType = CacheType> e
|
||||
| ModalComponentData
|
||||
| APIModalInteractionResponseCallbackData,
|
||||
): Promise<void>;
|
||||
/** @deprecated Sending a premium-style button is the new Discord behaviour. */
|
||||
public sendPremiumRequired(): Promise<void>;
|
||||
public awaitModalSubmit(
|
||||
options: AwaitModalSubmitOptions<ModalSubmitInteraction>,
|
||||
): Promise<ModalSubmitInteraction<Cached>>;
|
||||
private transformOption(
|
||||
option: APIApplicationCommandOption,
|
||||
// @ts-expect-error ws/1.x.
|
||||
resolved: APIApplicationCommandInteractionData['resolved'],
|
||||
): CommandInteractionOption<Cached>;
|
||||
}
|
||||
@@ -2027,6 +2029,12 @@ export class LimitedCollection<Key, Value> extends Collection<Key, Value> {
|
||||
public keepOverLimit: ((value: Value, key: Key, collection: this) => boolean) | null;
|
||||
}
|
||||
|
||||
export interface MessageCall {
|
||||
get endedAt(): Date | null;
|
||||
endedTimestamp: number | null;
|
||||
participants: readonly Snowflake[];
|
||||
}
|
||||
|
||||
export type MessageComponentType = Exclude<ComponentType, ComponentType.TextInput | ComponentType.ActionRow>;
|
||||
|
||||
export interface MessageCollectorOptionsParams<
|
||||
@@ -2118,6 +2126,7 @@ export class Message<InGuild extends boolean = boolean> extends Base {
|
||||
public get thread(): AnyThreadChannel | null;
|
||||
public tts: boolean;
|
||||
public poll: Poll | null;
|
||||
public call: MessageCall | null;
|
||||
public type: MessageType;
|
||||
public get url(): string;
|
||||
public webhookId: Snowflake | null;
|
||||
@@ -2254,6 +2263,7 @@ export class MessageComponentInteraction<Cached extends CacheType = CacheType> e
|
||||
| ModalComponentData
|
||||
| APIModalInteractionResponseCallbackData,
|
||||
): Promise<void>;
|
||||
/** @deprecated Sending a premium-style button is the new Discord behaviour. */
|
||||
public sendPremiumRequired(): Promise<void>;
|
||||
public awaitModalSubmit(
|
||||
options: AwaitModalSubmitOptions<ModalSubmitInteraction>,
|
||||
@@ -2453,6 +2463,7 @@ export class ModalSubmitInteraction<Cached extends CacheType = CacheType> extend
|
||||
options: InteractionDeferUpdateOptions & { fetchReply: true },
|
||||
): Promise<Message<BooleanCache<Cached>>>;
|
||||
public deferUpdate(options?: InteractionDeferUpdateOptions): Promise<InteractionResponse<BooleanCache<Cached>>>;
|
||||
/** @deprecated Sending a premium-style button is the new Discord behaviour. */
|
||||
public sendPremiumRequired(): Promise<void>;
|
||||
public inGuild(): this is ModalSubmitInteraction<'raw' | 'cached'>;
|
||||
public inCachedGuild(): this is ModalSubmitInteraction<'cached'>;
|
||||
@@ -3432,6 +3443,7 @@ export function parseWebhookURL(url: string): WebhookClientDataIdWithToken | nul
|
||||
/** @internal */
|
||||
export function transformResolved<Cached extends CacheType>(
|
||||
supportingData: SupportingInteractionResolvedData,
|
||||
// @ts-expect-error ws/1.x.
|
||||
data?: APIApplicationCommandInteractionData['resolved'],
|
||||
): CommandInteractionResolvedData<Cached>;
|
||||
export function resolveSKUId(resolvable: SKUResolvable): Snowflake | null;
|
||||
@@ -3646,7 +3658,7 @@ export class WebSocketManager extends EventEmitter {
|
||||
public on(event: GatewayDispatchEvents, listener: (data: any, shardId: number) => void): this;
|
||||
public once(event: GatewayDispatchEvents, listener: (data: any, shardId: number) => void): this;
|
||||
|
||||
private debug(message: string, shardId?: number): void;
|
||||
private debug(messages: readonly string[], shardId?: number): void;
|
||||
private connect(): Promise<void>;
|
||||
private broadcast(packet: unknown): void;
|
||||
private destroy(): Promise<void>;
|
||||
@@ -3677,7 +3689,7 @@ export class WebSocketShard extends EventEmitter {
|
||||
public status: Status;
|
||||
public ping: number;
|
||||
|
||||
private debug(message: string): void;
|
||||
private debug(messages: readonly string[]): void;
|
||||
private onReadyPacket(packet: unknown): void;
|
||||
private gotGuild(guildId: Snowflake): void;
|
||||
private checkReady(): void;
|
||||
@@ -4062,7 +4074,7 @@ export class ApplicationCommandManager<
|
||||
id: Snowflake,
|
||||
options: FetchApplicationCommandOptions & { guildId: Snowflake },
|
||||
): Promise<ApplicationCommand>;
|
||||
public fetch(options: FetchApplicationCommandOptions): Promise<Collection<string, ApplicationCommandScope>>;
|
||||
public fetch(options: FetchApplicationCommandOptions): Promise<Collection<Snowflake, ApplicationCommandScope>>;
|
||||
public fetch(id: Snowflake, options?: FetchApplicationCommandOptions): Promise<ApplicationCommandScope>;
|
||||
public fetch(
|
||||
id?: Snowflake,
|
||||
@@ -5774,6 +5786,11 @@ interface GuildAuditLogsTypes {
|
||||
[AuditLogEvent.AutoModerationBlockMessage]: ['AutoModerationRule', 'Create'];
|
||||
[AuditLogEvent.AutoModerationFlagToChannel]: ['AutoModerationRule', 'Create'];
|
||||
[AuditLogEvent.AutoModerationUserCommunicationDisabled]: ['AutoModerationRule', 'Create'];
|
||||
[AuditLogEvent.OnboardingPromptCreate]: ['GuildOnboardingPrompt', 'Create'];
|
||||
[AuditLogEvent.OnboardingPromptUpdate]: ['GuildOnboardingPrompt', 'Update'];
|
||||
[AuditLogEvent.OnboardingPromptDelete]: ['GuildOnboardingPrompt', 'Delete'];
|
||||
[AuditLogEvent.OnboardingCreate]: ['GuildOnboarding', 'Create'];
|
||||
[AuditLogEvent.OnboardingUpdate]: ['GuildOnboarding', 'Update'];
|
||||
}
|
||||
|
||||
export type GuildAuditLogsActionType = GuildAuditLogsTypes[keyof GuildAuditLogsTypes][1] | 'All';
|
||||
@@ -5838,6 +5855,7 @@ export interface GuildAuditLogsEntryTargetField<TActionType extends GuildAuditLo
|
||||
GuildScheduledEvent: GuildScheduledEvent;
|
||||
ApplicationCommand: ApplicationCommand | { id: Snowflake };
|
||||
AutoModerationRule: AutoModerationRule;
|
||||
GuildOnboardingPrompt: GuildOnboardingPrompt;
|
||||
}
|
||||
|
||||
export interface GuildAuditLogsFetchOptions<Event extends GuildAuditLogsResolvable> {
|
||||
|
||||
@@ -206,7 +206,7 @@ import {
|
||||
MentionableSelectMenuComponent,
|
||||
Poll,
|
||||
} from '.';
|
||||
import { expectAssignable, expectNotAssignable, expectNotType, expectType } from 'tsd';
|
||||
import { expectAssignable, expectDeprecated, expectNotAssignable, expectNotType, expectType } from 'tsd';
|
||||
import type { ContextMenuCommandBuilder, SlashCommandBuilder } from '@discordjs/builders';
|
||||
import { ReadonlyCollection } from '@discordjs/collection';
|
||||
|
||||
@@ -1763,6 +1763,7 @@ client.on('interactionCreate', async interaction => {
|
||||
expectType<AnySelectMenuInteraction | ButtonInteraction>(interaction);
|
||||
expectType<MessageActionRowComponent | APIButtonComponent | APISelectMenuComponent>(interaction.component);
|
||||
expectType<Message>(interaction.message);
|
||||
expectDeprecated(interaction.sendPremiumRequired());
|
||||
if (interaction.inCachedGuild()) {
|
||||
expectAssignable<MessageComponentInteraction>(interaction);
|
||||
expectType<MessageActionRowComponent>(interaction.component);
|
||||
@@ -1950,6 +1951,7 @@ client.on('interactionCreate', async interaction => {
|
||||
interaction.type === InteractionType.ApplicationCommand &&
|
||||
interaction.commandType === ApplicationCommandType.ChatInput
|
||||
) {
|
||||
expectDeprecated(interaction.sendPremiumRequired());
|
||||
if (interaction.inRawGuild()) {
|
||||
expectNotAssignable<Interaction<'cached'>>(interaction);
|
||||
expectAssignable<ChatInputCommandInteraction>(interaction);
|
||||
@@ -2073,6 +2075,10 @@ client.on('interactionCreate', async interaction => {
|
||||
expectType<Promise<Message>>(interaction.followUp({ content: 'a' }));
|
||||
}
|
||||
}
|
||||
|
||||
if (interaction.isModalSubmit()) {
|
||||
expectDeprecated(interaction.sendPremiumRequired());
|
||||
}
|
||||
});
|
||||
|
||||
declare const shard: Shard;
|
||||
|
||||
@@ -60,22 +60,22 @@
|
||||
"homepage": "https://discord.js.org",
|
||||
"funding": "https://github.com/discordjs/discord.js?sponsor",
|
||||
"dependencies": {
|
||||
"commander": "^12.0.0",
|
||||
"commander": "^12.1.0",
|
||||
"jsdoc-to-markdown": "^8.0.1",
|
||||
"tslib": "^2.6.2",
|
||||
"typedoc": "^0.25.12"
|
||||
"typedoc": "^0.25.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@favware/cliff-jumper": "^3.0.2",
|
||||
"@favware/cliff-jumper": "^3.0.3",
|
||||
"@types/jsdoc-to-markdown": "^7.0.6",
|
||||
"@types/node": "18.18.8",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"prettier": "^3.2.5",
|
||||
"tsup": "^8.0.2",
|
||||
"turbo": "^1.13.2",
|
||||
"prettier": "^3.3.0",
|
||||
"tsup": "^8.1.0",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { URL } from 'node:url';
|
||||
import { describe, test, expect, vitest } from 'vitest';
|
||||
import {
|
||||
applicationDirectory,
|
||||
chatInputApplicationCommandMention,
|
||||
blockQuote,
|
||||
bold,
|
||||
@@ -313,6 +314,20 @@ describe('Message formatters', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('applicationDirectory', () => {
|
||||
test('GIVEN application id THEN returns application directory store', () => {
|
||||
expect(applicationDirectory('123456789012345678')).toEqual(
|
||||
'https://discord.com/application-directory/123456789012345678/store',
|
||||
);
|
||||
});
|
||||
|
||||
test('GIVEN application id AND SKU id THEN returns SKU within the application directory store', () => {
|
||||
expect(applicationDirectory('123456789012345678', '123456789012345678')).toEqual(
|
||||
'https://discord.com/application-directory/123456789012345678/store/123456789012345678',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Faces', () => {
|
||||
test('GIVEN Faces.Shrug THEN returns "¯\\_(ツ)_/¯"', () => {
|
||||
expect<'¯\\_(ツ)_/¯'>(Faces.Shrug).toEqual('¯\\_(ツ)_/¯');
|
||||
|
||||
@@ -55,24 +55,24 @@
|
||||
"homepage": "https://discord.js.org",
|
||||
"funding": "https://github.com/discordjs/discord.js?sponsor",
|
||||
"dependencies": {
|
||||
"discord-api-types": "0.37.83"
|
||||
"discord-api-types": "^0.37.114"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@discordjs/api-extractor": "workspace:^",
|
||||
"@discordjs/scripts": "workspace:^",
|
||||
"@favware/cliff-jumper": "^3.0.2",
|
||||
"@favware/cliff-jumper": "^3.0.3",
|
||||
"@types/node": "16.18.60",
|
||||
"@vitest/coverage-v8": "^1.5.0",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"esbuild-plugin-version-injector": "^1.2.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"prettier": "^3.2.5",
|
||||
"tsup": "^8.0.2",
|
||||
"turbo": "^1.13.2",
|
||||
"prettier": "^3.3.0",
|
||||
"tsup": "^8.1.0",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5",
|
||||
"vitest": "^1.5.0"
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.11.0"
|
||||
|
||||
@@ -615,6 +615,39 @@ export function time(timeOrSeconds?: Date | number, style?: TimestampStylesStrin
|
||||
return typeof style === 'string' ? `<t:${timeOrSeconds}:${style}>` : `<t:${timeOrSeconds}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an application directory link.
|
||||
*
|
||||
* @typeParam ApplicationId - This is inferred by the supplied application id
|
||||
* @param applicationId - The application id
|
||||
*/
|
||||
export function applicationDirectory<ApplicationId extends Snowflake>(
|
||||
applicationId: ApplicationId,
|
||||
): `https://discord.com/application-directory/${ApplicationId}/store`;
|
||||
|
||||
/**
|
||||
* Formats an application directory SKU link.
|
||||
*
|
||||
* @typeParam ApplicationId - This is inferred by the supplied application id
|
||||
* @typeParam SKUId - This is inferred by the supplied SKU id
|
||||
* @param applicationId - The application id
|
||||
* @param skuId - The SKU id
|
||||
*/
|
||||
export function applicationDirectory<ApplicationId extends Snowflake, SKUId extends Snowflake>(
|
||||
applicationId: ApplicationId,
|
||||
skuId: SKUId,
|
||||
): `https://discord.com/application-directory/${ApplicationId}/store/${SKUId}`;
|
||||
|
||||
export function applicationDirectory<ApplicationId extends Snowflake, SKUId extends Snowflake>(
|
||||
applicationId: ApplicationId,
|
||||
skuId?: SKUId,
|
||||
):
|
||||
| `https://discord.com/application-directory/${ApplicationId}/store/${SKUId}`
|
||||
| `https://discord.com/application-directory/${ApplicationId}/store` {
|
||||
const url = `https://discord.com/application-directory/${applicationId}/store` as const;
|
||||
return skuId ? `${url}/${skuId}` : url;
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link https://discord.com/developers/docs/reference#message-formatting-timestamp-styles | message formatting timestamp styles}
|
||||
* supported by Discord.
|
||||
|
||||
@@ -72,24 +72,24 @@
|
||||
"@discordjs/rest": "workspace:^",
|
||||
"@discordjs/util": "workspace:^",
|
||||
"@discordjs/ws": "workspace:^",
|
||||
"discord-api-types": "0.37.83"
|
||||
"discord-api-types": "^0.37.114"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@discordjs/api-extractor": "workspace:^",
|
||||
"@discordjs/scripts": "workspace:^",
|
||||
"@favware/cliff-jumper": "^3.0.2",
|
||||
"@favware/cliff-jumper": "^3.0.3",
|
||||
"@types/node": "18.18.8",
|
||||
"@vitest/coverage-v8": "^1.5.0",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"esbuild-plugin-version-injector": "^1.2.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"prettier": "^3.2.5",
|
||||
"tsup": "^8.0.2",
|
||||
"turbo": "^1.13.2",
|
||||
"prettier": "^3.3.0",
|
||||
"tsup": "^8.1.0",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5",
|
||||
"vitest": "^1.5.0"
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
||||
@@ -55,9 +55,9 @@
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"prettier": "^3.2.5",
|
||||
"tsup": "^8.0.2",
|
||||
"turbo": "^1.13.2",
|
||||
"prettier": "^3.3.0",
|
||||
"tsup": "^8.1.0",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -68,26 +68,26 @@
|
||||
"@discordjs/rest": "workspace:^",
|
||||
"@discordjs/util": "workspace:^",
|
||||
"tslib": "^2.6.2",
|
||||
"undici": "6.13.0"
|
||||
"undici": "6.18.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@discordjs/api-extractor": "workspace:^",
|
||||
"@discordjs/scripts": "workspace:^",
|
||||
"@favware/cliff-jumper": "^3.0.2",
|
||||
"@favware/cliff-jumper": "^3.0.3",
|
||||
"@types/node": "18.18.8",
|
||||
"@types/supertest": "^6.0.2",
|
||||
"@vitest/coverage-v8": "^1.5.0",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"esbuild-plugin-version-injector": "^1.2.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"prettier": "^3.2.5",
|
||||
"supertest": "^6.3.4",
|
||||
"tsup": "^8.0.2",
|
||||
"turbo": "^1.13.2",
|
||||
"prettier": "^3.3.0",
|
||||
"supertest": "^7.0.0",
|
||||
"tsup": "^8.1.0",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5",
|
||||
"vitest": "^1.5.0"
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
||||
@@ -1,114 +1,119 @@
|
||||
import { test, expect } from 'vitest';
|
||||
import { CDN } from '../src/index.js';
|
||||
|
||||
const base = 'https://discord.com';
|
||||
const baseCDN = 'https://cdn-discord.com';
|
||||
const baseMedia = 'https://media-discord.com';
|
||||
const id = '123456';
|
||||
const hash = 'abcdef';
|
||||
const animatedHash = 'a_bcdef';
|
||||
const defaultAvatar = 1_234 % 5;
|
||||
|
||||
const cdn = new CDN(base);
|
||||
const cdn = new CDN(baseCDN, baseMedia);
|
||||
|
||||
test('appAsset default', () => {
|
||||
expect(cdn.appAsset(id, hash)).toEqual(`${base}/app-assets/${id}/${hash}.webp`);
|
||||
expect(cdn.appAsset(id, hash)).toEqual(`${baseCDN}/app-assets/${id}/${hash}.webp`);
|
||||
});
|
||||
|
||||
test('appIcon default', () => {
|
||||
expect(cdn.appIcon(id, hash)).toEqual(`${base}/app-icons/${id}/${hash}.webp`);
|
||||
expect(cdn.appIcon(id, hash)).toEqual(`${baseCDN}/app-icons/${id}/${hash}.webp`);
|
||||
});
|
||||
|
||||
test('avatar default', () => {
|
||||
expect(cdn.avatar(id, hash)).toEqual(`${base}/avatars/${id}/${hash}.webp`);
|
||||
expect(cdn.avatar(id, hash)).toEqual(`${baseCDN}/avatars/${id}/${hash}.webp`);
|
||||
});
|
||||
|
||||
test('avatar dynamic-animated', () => {
|
||||
expect(cdn.avatar(id, animatedHash)).toEqual(`${base}/avatars/${id}/${animatedHash}.gif`);
|
||||
expect(cdn.avatar(id, animatedHash)).toEqual(`${baseCDN}/avatars/${id}/${animatedHash}.gif`);
|
||||
});
|
||||
|
||||
test('avatar dynamic-not-animated', () => {
|
||||
expect(cdn.avatar(id, hash)).toEqual(`${base}/avatars/${id}/${hash}.webp`);
|
||||
expect(cdn.avatar(id, hash)).toEqual(`${baseCDN}/avatars/${id}/${hash}.webp`);
|
||||
});
|
||||
|
||||
test('avatar decoration default', () => {
|
||||
expect(cdn.avatarDecoration(id, hash)).toEqual(`${base}/avatar-decorations/${id}/${hash}.webp`);
|
||||
expect(cdn.avatarDecoration(id, hash)).toEqual(`${baseCDN}/avatar-decorations/${id}/${hash}.webp`);
|
||||
});
|
||||
|
||||
test('avatar decoration preset', () => {
|
||||
expect(cdn.avatarDecoration(hash)).toEqual(`${base}/avatar-decoration-presets/${hash}.png`);
|
||||
expect(cdn.avatarDecoration(hash)).toEqual(`${baseCDN}/avatar-decoration-presets/${hash}.png`);
|
||||
});
|
||||
|
||||
test('banner default', () => {
|
||||
expect(cdn.banner(id, hash)).toEqual(`${base}/banners/${id}/${hash}.webp`);
|
||||
expect(cdn.banner(id, hash)).toEqual(`${baseCDN}/banners/${id}/${hash}.webp`);
|
||||
});
|
||||
|
||||
test('channelIcon default', () => {
|
||||
expect(cdn.channelIcon(id, hash)).toEqual(`${base}/channel-icons/${id}/${hash}.webp`);
|
||||
expect(cdn.channelIcon(id, hash)).toEqual(`${baseCDN}/channel-icons/${id}/${hash}.webp`);
|
||||
});
|
||||
|
||||
test('defaultAvatar default', () => {
|
||||
expect(cdn.defaultAvatar(defaultAvatar)).toEqual(`${base}/embed/avatars/${defaultAvatar}.png`);
|
||||
expect(cdn.defaultAvatar(defaultAvatar)).toEqual(`${baseCDN}/embed/avatars/${defaultAvatar}.png`);
|
||||
});
|
||||
|
||||
test('discoverySplash default', () => {
|
||||
expect(cdn.discoverySplash(id, hash)).toEqual(`${base}/discovery-splashes/${id}/${hash}.webp`);
|
||||
expect(cdn.discoverySplash(id, hash)).toEqual(`${baseCDN}/discovery-splashes/${id}/${hash}.webp`);
|
||||
});
|
||||
|
||||
test('emoji default', () => {
|
||||
expect(cdn.emoji(id)).toEqual(`${base}/emojis/${id}.webp`);
|
||||
expect(cdn.emoji(id)).toEqual(`${baseCDN}/emojis/${id}.webp`);
|
||||
});
|
||||
|
||||
test('emoji gif', () => {
|
||||
expect(cdn.emoji(id, 'gif')).toEqual(`${base}/emojis/${id}.gif`);
|
||||
expect(cdn.emoji(id, 'gif')).toEqual(`${baseCDN}/emojis/${id}.gif`);
|
||||
});
|
||||
|
||||
test('guildMemberAvatar default', () => {
|
||||
expect(cdn.guildMemberAvatar(id, id, hash)).toEqual(`${base}/guilds/${id}/users/${id}/avatars/${hash}.webp`);
|
||||
expect(cdn.guildMemberAvatar(id, id, hash)).toEqual(`${baseCDN}/guilds/${id}/users/${id}/avatars/${hash}.webp`);
|
||||
});
|
||||
|
||||
test('guildMemberAvatar dynamic-animated', () => {
|
||||
expect(cdn.guildMemberAvatar(id, id, animatedHash)).toEqual(
|
||||
`${base}/guilds/${id}/users/${id}/avatars/${animatedHash}.gif`,
|
||||
`${baseCDN}/guilds/${id}/users/${id}/avatars/${animatedHash}.gif`,
|
||||
);
|
||||
});
|
||||
|
||||
test('guildMemberAvatar dynamic-not-animated', () => {
|
||||
expect(cdn.guildMemberAvatar(id, id, hash)).toEqual(`${base}/guilds/${id}/users/${id}/avatars/${hash}.webp`);
|
||||
expect(cdn.guildMemberAvatar(id, id, hash)).toEqual(`${baseCDN}/guilds/${id}/users/${id}/avatars/${hash}.webp`);
|
||||
});
|
||||
|
||||
test('guildScheduledEventCover default', () => {
|
||||
expect(cdn.guildScheduledEventCover(id, hash)).toEqual(`${base}/guild-events/${id}/${hash}.webp`);
|
||||
expect(cdn.guildScheduledEventCover(id, hash)).toEqual(`${baseCDN}/guild-events/${id}/${hash}.webp`);
|
||||
});
|
||||
|
||||
test('icon default', () => {
|
||||
expect(cdn.icon(id, hash)).toEqual(`${base}/icons/${id}/${hash}.webp`);
|
||||
expect(cdn.icon(id, hash)).toEqual(`${baseCDN}/icons/${id}/${hash}.webp`);
|
||||
});
|
||||
|
||||
test('icon dynamic-animated', () => {
|
||||
expect(cdn.icon(id, animatedHash)).toEqual(`${base}/icons/${id}/${animatedHash}.gif`);
|
||||
expect(cdn.icon(id, animatedHash)).toEqual(`${baseCDN}/icons/${id}/${animatedHash}.gif`);
|
||||
});
|
||||
|
||||
test('icon dynamic-not-animated', () => {
|
||||
expect(cdn.icon(id, hash)).toEqual(`${base}/icons/${id}/${hash}.webp`);
|
||||
expect(cdn.icon(id, hash)).toEqual(`${baseCDN}/icons/${id}/${hash}.webp`);
|
||||
});
|
||||
|
||||
test('role icon default', () => {
|
||||
expect(cdn.roleIcon(id, hash)).toEqual(`${base}/role-icons/${id}/${hash}.webp`);
|
||||
expect(cdn.roleIcon(id, hash)).toEqual(`${baseCDN}/role-icons/${id}/${hash}.webp`);
|
||||
});
|
||||
|
||||
test('splash default', () => {
|
||||
expect(cdn.splash(id, hash)).toEqual(`${base}/splashes/${id}/${hash}.webp`);
|
||||
expect(cdn.splash(id, hash)).toEqual(`${baseCDN}/splashes/${id}/${hash}.webp`);
|
||||
});
|
||||
|
||||
test('sticker default', () => {
|
||||
expect(cdn.sticker(id)).toEqual(`${base}/stickers/${id}.png`);
|
||||
expect(cdn.sticker(id)).toEqual(`${baseCDN}/stickers/${id}.png`);
|
||||
});
|
||||
|
||||
test('sticker GIF', () => {
|
||||
expect(cdn.sticker(id, 'gif')).toEqual(`${baseMedia}/stickers/${id}.gif`);
|
||||
});
|
||||
|
||||
test('stickerPackBanner default', () => {
|
||||
expect(cdn.stickerPackBanner(id)).toEqual(`${base}/app-assets/710982414301790216/store/${id}.webp`);
|
||||
expect(cdn.stickerPackBanner(id)).toEqual(`${baseCDN}/app-assets/710982414301790216/store/${id}.webp`);
|
||||
});
|
||||
|
||||
test('teamIcon default', () => {
|
||||
expect(cdn.teamIcon(id, hash)).toEqual(`${base}/team-icons/${id}/${hash}.webp`);
|
||||
expect(cdn.teamIcon(id, hash)).toEqual(`${baseCDN}/team-icons/${id}/${hash}.webp`);
|
||||
});
|
||||
|
||||
test('makeURL throws on invalid size', () => {
|
||||
@@ -122,5 +127,5 @@ test('makeURL throws on invalid extension', () => {
|
||||
});
|
||||
|
||||
test('makeURL valid size', () => {
|
||||
expect(cdn.avatar(id, animatedHash, { size: 512 })).toEqual(`${base}/avatars/${id}/${animatedHash}.gif?size=512`);
|
||||
expect(cdn.avatar(id, animatedHash, { size: 512 })).toEqual(`${baseCDN}/avatars/${id}/${animatedHash}.gif?size=512`);
|
||||
});
|
||||
|
||||
@@ -88,27 +88,27 @@
|
||||
"@sapphire/async-queue": "^1.5.2",
|
||||
"@sapphire/snowflake": "^3.5.3",
|
||||
"@vladfrangu/async_event_emitter": "^2.2.4",
|
||||
"discord-api-types": "0.37.83",
|
||||
"discord-api-types": "^0.37.114",
|
||||
"magic-bytes.js": "^1.10.0",
|
||||
"tslib": "^2.6.2",
|
||||
"undici": "6.13.0"
|
||||
"undici": "6.18.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@discordjs/api-extractor": "workspace:^",
|
||||
"@discordjs/scripts": "workspace:^",
|
||||
"@favware/cliff-jumper": "^3.0.2",
|
||||
"@favware/cliff-jumper": "^3.0.3",
|
||||
"@types/node": "18.17.9",
|
||||
"@vitest/coverage-v8": "^1.5.0",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"esbuild-plugin-version-injector": "^1.2.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"prettier": "^3.2.5",
|
||||
"tsup": "^8.0.2",
|
||||
"turbo": "^1.13.2",
|
||||
"prettier": "^3.3.0",
|
||||
"tsup": "^8.1.0",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5",
|
||||
"vitest": "^1.5.0"
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.11.0"
|
||||
|
||||
@@ -46,6 +46,12 @@ export interface MakeURLOptions {
|
||||
* The allowed extensions that can be used
|
||||
*/
|
||||
allowedExtensions?: readonly string[];
|
||||
/**
|
||||
* The base URL.
|
||||
*
|
||||
* @defaultValue `DefaultRestOptions.cdn`
|
||||
*/
|
||||
base?: string;
|
||||
/**
|
||||
* The extension to use for the image URL
|
||||
*
|
||||
@@ -62,7 +68,10 @@ export interface MakeURLOptions {
|
||||
* The CDN link builder
|
||||
*/
|
||||
export class CDN {
|
||||
public constructor(private readonly base: string = DefaultRestOptions.cdn) {}
|
||||
public constructor(
|
||||
private readonly cdn: string = DefaultRestOptions.cdn,
|
||||
private readonly mediaProxy: string = DefaultRestOptions.mediaProxy,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Generates an app asset URL for a client's asset.
|
||||
@@ -287,10 +296,15 @@ export class CDN {
|
||||
* @param stickerId - The sticker id
|
||||
* @param extension - The extension of the sticker
|
||||
* @privateRemarks
|
||||
* Stickers cannot have a `.webp` extension, so we default to a `.png`
|
||||
* Stickers cannot have a `.webp` extension, so we default to a `.png`.
|
||||
* Sticker GIFs do not use the CDN base URL.
|
||||
*/
|
||||
public sticker(stickerId: string, extension: StickerExtension = 'png'): string {
|
||||
return this.makeURL(`/stickers/${stickerId}`, { allowedExtensions: ALLOWED_STICKER_EXTENSIONS, extension });
|
||||
return this.makeURL(`/stickers/${stickerId}`, {
|
||||
allowedExtensions: ALLOWED_STICKER_EXTENSIONS,
|
||||
base: extension === 'gif' ? this.mediaProxy : this.cdn,
|
||||
extension,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -352,7 +366,12 @@ export class CDN {
|
||||
*/
|
||||
private makeURL(
|
||||
route: string,
|
||||
{ allowedExtensions = ALLOWED_EXTENSIONS, extension = 'webp', size }: Readonly<MakeURLOptions> = {},
|
||||
{
|
||||
allowedExtensions = ALLOWED_EXTENSIONS,
|
||||
base = this.cdn,
|
||||
extension = 'webp',
|
||||
size,
|
||||
}: Readonly<MakeURLOptions> = {},
|
||||
): string {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
extension = String(extension).toLowerCase();
|
||||
@@ -365,7 +384,7 @@ export class CDN {
|
||||
throw new RangeError(`Invalid size provided: ${size}\nMust be one of: ${ALLOWED_SIZES.join(', ')}`);
|
||||
}
|
||||
|
||||
const url = new URL(`${this.base}${route}.${extension}`);
|
||||
const url = new URL(`${base}${route}.${extension}`);
|
||||
|
||||
if (size) {
|
||||
url.searchParams.set('size', String(size));
|
||||
|
||||
@@ -75,7 +75,7 @@ export class REST extends AsyncEventEmitter<RestEvents> {
|
||||
|
||||
public constructor(options: Partial<RESTOptions> = {}) {
|
||||
super();
|
||||
this.cdn = new CDN(options.cdn ?? DefaultRestOptions.cdn);
|
||||
this.cdn = new CDN(options.cdn ?? DefaultRestOptions.cdn, options.mediaProxy ?? DefaultRestOptions.mediaProxy);
|
||||
this.options = { ...DefaultRestOptions, ...options };
|
||||
this.globalRemaining = Math.max(1, this.options.globalRequestsPerSecond);
|
||||
this.agent = options.agent ?? null;
|
||||
|
||||
@@ -31,6 +31,7 @@ export const DefaultRestOptions = {
|
||||
async makeRequest(...args): Promise<ResponseLike> {
|
||||
return getDefaultStrategy()(...args);
|
||||
},
|
||||
mediaProxy: 'https://media.discordapp.net',
|
||||
} as const satisfies Required<RESTOptions>;
|
||||
|
||||
/**
|
||||
|
||||
@@ -85,6 +85,12 @@ export interface RESTOptions {
|
||||
* For example, to use global fetch, simply provide `makeRequest: fetch`
|
||||
*/
|
||||
makeRequest(url: string, init: RequestInit): Promise<ResponseLike>;
|
||||
/**
|
||||
* The media proxy path
|
||||
*
|
||||
* @defaultValue `'https://media.discordapp.net'`
|
||||
*/
|
||||
mediaProxy: string;
|
||||
/**
|
||||
* The extra offset to add to rate limits in milliseconds
|
||||
*
|
||||
|
||||
@@ -66,25 +66,25 @@
|
||||
"@microsoft/tsdoc-config": "0.16.2",
|
||||
"@vercel/blob": "^0.22.3",
|
||||
"@vercel/postgres": "^0.8.0",
|
||||
"commander": "^12.0.0",
|
||||
"commander": "^12.1.0",
|
||||
"tslib": "^2.6.2",
|
||||
"undici": "6.13.0",
|
||||
"yaml": "2.4.1"
|
||||
"undici": "6.18.2",
|
||||
"yaml": "2.4.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@turbo/gen": "^1.12.5",
|
||||
"@turbo/gen": "^1.13.3",
|
||||
"@types/node": "18.18.8",
|
||||
"@vitest/coverage-v8": "^1.5.0",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"env-cmd": "^10.1.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"prettier": "^3.2.5",
|
||||
"tsup": "^8.0.2",
|
||||
"turbo": "^1.13.2",
|
||||
"prettier": "^3.3.0",
|
||||
"tsup": "^8.1.0",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5",
|
||||
"vitest": "^1.5.0"
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
||||
@@ -240,7 +240,12 @@ function itemExcerptText(excerpt: Excerpt, apiPackage: ApiPackage) {
|
||||
// dapi-types doesn't have routes for class members
|
||||
// so we can assume this member is for an enum
|
||||
if (meaning === 'member' && path && 'parent' in path) {
|
||||
href += `/enum/${path.parent}#${path.component}`;
|
||||
// unless it's a variable like FormattingPatterns.Role
|
||||
if (path.parent.toString() === '__type') {
|
||||
href += `#${token.text.split('.')[0]}`;
|
||||
} else {
|
||||
href += `/enum/${path.parent}#${path.component}`;
|
||||
}
|
||||
} else if (meaning === 'type' || meaning === 'var') {
|
||||
href += `#${token.text}`;
|
||||
} else {
|
||||
@@ -951,11 +956,16 @@ export async function generateSplitDocumentation({
|
||||
|
||||
const members = entry.members
|
||||
.filter((item) => {
|
||||
if (item.kind !== 'Function') {
|
||||
return true;
|
||||
switch (item.kind) {
|
||||
case ApiItemKind.Function:
|
||||
return (item as ApiFunction).overloadIndex === 1;
|
||||
case ApiItemKind.Interface:
|
||||
return !entry.members.some(
|
||||
(innerItem) => innerItem.kind === ApiItemKind.Class && innerItem.displayName === item.displayName,
|
||||
);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
return (item as ApiFunction).overloadIndex === 1;
|
||||
})
|
||||
.map((item) => ({
|
||||
kind: item.kind,
|
||||
|
||||
@@ -41,14 +41,15 @@ export default function generator(plop: PlopTypes.NodePlopAPI): void {
|
||||
{
|
||||
type: 'addMany',
|
||||
destination: `${plop.getDestBasePath()}/../{{name}}`,
|
||||
templateFiles: ['templates/**'],
|
||||
// plop doesn't like our cliff.toml file since it tries to parse it. we add it manually later
|
||||
templateFiles: ['templates/**', '!templates/default/cliff.toml'],
|
||||
globOptions: { dot: true },
|
||||
base: 'templates/default/',
|
||||
stripExtensions: ['hbs'],
|
||||
},
|
||||
{
|
||||
type: 'modify',
|
||||
path: `${plop.getDestBasePath()}/turbo/generators/templates/cliff.toml`,
|
||||
path: `${plop.getDestBasePath()}/turbo/generators/templates/default/cliff.toml`,
|
||||
async transform(content, answers) {
|
||||
const cliffTOML = content.replace('{{name}}', answers.name);
|
||||
await writeFile(`${plop.getDestBasePath()}/../${answers.name}/cliff.toml`, cliffTOML);
|
||||
@@ -70,10 +71,17 @@ export default function generator(plop: PlopTypes.NodePlopAPI): void {
|
||||
type: 'modify',
|
||||
path: `${plop.getDestBasePath()}/../../.github/labeler.yml`,
|
||||
transform(content, answers) {
|
||||
const labelerYAML = parseYAML(content) as Record<string, string[]>;
|
||||
labelerYAML[`packages:${answers.name}`] = [`packages/${answers.name}/*`, `packages/${answers.name}/**/*`];
|
||||
const labelerYAML = parseYAML(content) as Record<string, Record<string, Record<string, string[]>[]>[]>;
|
||||
|
||||
return stringifyYAML(sortYAMLObject(labelerYAML));
|
||||
labelerYAML[`packages:${answers.name}`] = [
|
||||
{
|
||||
'changed-files': [
|
||||
{ 'any-glob-to-any-file': [`packages/${answers.name}/*`, `packages/${answers.name}/**/*`] },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return stringifyYAML(labelerYAML, { sortMapEntries: true });
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# Packages node_modules # Log files logs *.log npm-debug.log* # Runtime data pids *.pid *.seed # Env .env # Dist dist
|
||||
dist-docs # Docs docs/**/* !docs/README.md # Miscellaneous .turbo .tmp coverage
|
||||
dist-docs # Docs docs/**/* !docs/README.md # Miscellaneous .turbo .tmp coverage
|
||||
@@ -58,37 +58,37 @@
|
||||
"react-dom": "^18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@favware/cliff-jumper": "^3.0.2",
|
||||
"@favware/cliff-jumper": "^3.0.3",
|
||||
"@react-icons/all-files": "^4.1.0",
|
||||
"@storybook/addon-essentials": "^8.0.8",
|
||||
"@storybook/addon-interactions": "^8.0.8",
|
||||
"@storybook/addon-links": "^8.0.8",
|
||||
"@storybook/addon-essentials": "^8.1.5",
|
||||
"@storybook/addon-interactions": "^8.1.5",
|
||||
"@storybook/addon-links": "^8.1.5",
|
||||
"@storybook/addon-styling": "^1.3.7",
|
||||
"@storybook/blocks": "^8.0.8",
|
||||
"@storybook/react": "^8.0.8",
|
||||
"@storybook/react-vite": "^8.0.8",
|
||||
"@storybook/blocks": "^8.1.5",
|
||||
"@storybook/react": "^8.1.5",
|
||||
"@storybook/react-vite": "^8.1.5",
|
||||
"@storybook/testing-library": "^0.2.2",
|
||||
"@types/node": "18.18.8",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@unocss/eslint-plugin": "^0.60.2",
|
||||
"@unocss/reset": "^0.60.2",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"@unocss/eslint-plugin": "^0.60.4",
|
||||
"@unocss/reset": "^0.60.4",
|
||||
"@vitejs/plugin-react": "^4.3.0",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"chromatic": "^11.3.0",
|
||||
"chromatic": "^11.5.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier": "^3.3.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"storybook": "^8.0.8",
|
||||
"turbo": "^1.13.2",
|
||||
"storybook": "^8.1.5",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5",
|
||||
"unocss": "^0.60.2",
|
||||
"vite": "^5.2.9",
|
||||
"vite-plugin-dts": "^3.8.3",
|
||||
"vitest": "^1.5.0"
|
||||
"unocss": "^0.60.4",
|
||||
"vite": "^5.2.12",
|
||||
"vite-plugin-dts": "^3.9.1",
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
||||
@@ -64,20 +64,20 @@
|
||||
"devDependencies": {
|
||||
"@discordjs/api-extractor": "workspace:^",
|
||||
"@discordjs/scripts": "workspace:^",
|
||||
"@favware/cliff-jumper": "^3.0.2",
|
||||
"@favware/cliff-jumper": "^3.0.3",
|
||||
"@types/node": "16.18.60",
|
||||
"@vitest/coverage-v8": "^1.5.0",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"esbuild-plugin-version-injector": "^1.2.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"prettier": "^3.2.5",
|
||||
"tsd": "^0.30.7",
|
||||
"tsup": "^8.0.2",
|
||||
"turbo": "^1.13.2",
|
||||
"prettier": "^3.3.0",
|
||||
"tsd": "^0.31.0",
|
||||
"tsup": "^8.1.0",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5",
|
||||
"vitest": "^1.5.0"
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.11.0"
|
||||
|
||||
@@ -64,18 +64,18 @@
|
||||
"funding": "https://github.com/discordjs/discord.js?sponsor",
|
||||
"dependencies": {
|
||||
"@types/ws": "^8.5.10",
|
||||
"discord-api-types": "0.37.83",
|
||||
"discord-api-types": "^0.37.114",
|
||||
"prism-media": "^1.3.5",
|
||||
"tslib": "^2.6.2",
|
||||
"ws": "^8.16.0"
|
||||
"ws": "^8.17.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.4",
|
||||
"@babel/preset-env": "^7.24.4",
|
||||
"@babel/preset-typescript": "^7.24.1",
|
||||
"@babel/core": "^7.24.6",
|
||||
"@babel/preset-env": "^7.24.6",
|
||||
"@babel/preset-typescript": "^7.24.6",
|
||||
"@discordjs/api-extractor": "workspace:^",
|
||||
"@discordjs/scripts": "workspace:^",
|
||||
"@favware/cliff-jumper": "^3.0.2",
|
||||
"@favware/cliff-jumper": "^3.0.3",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/node": "16.18.60",
|
||||
"cross-env": "^7.0.3",
|
||||
@@ -86,9 +86,9 @@
|
||||
"jest": "^29.7.0",
|
||||
"jest-websocket-mock": "^2.5.0",
|
||||
"mock-socket": "^9.3.1",
|
||||
"prettier": "^3.2.5",
|
||||
"tsup": "^8.0.2",
|
||||
"turbo": "^1.13.2",
|
||||
"prettier": "^3.3.0",
|
||||
"tsup": "^8.1.0",
|
||||
"turbo": "^1.13.3",
|
||||
"tweetnacl": "^1.0.3",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
|
||||
@@ -2,6 +2,76 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
# [@discordjs/ws@1.2.0](https://github.com/discordjs/discord.js/compare/@discordjs/ws@1.1.1...@discordjs/ws@1.2.0) - (2025-01-01)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **SimpleIdentifyThrottler:** Don't sleep negative amounts ([a589c6d](https://github.com/discordjs/discord.js/commit/a589c6d49265d24cf202e8f68c6b2ad4fafd398c))
|
||||
- Retry for EAI_AGAIN I/O error (#10383) ([5b8a08e](https://github.com/discordjs/discord.js/commit/5b8a08ebb66276320a5095630ecee403783afec0))
|
||||
- Consistent debug log spacing (#10349) ([c6710e5](https://github.com/discordjs/discord.js/commit/c6710e56cc634ecb2b922d777fe715c49fa91baa))
|
||||
|
||||
## Features
|
||||
|
||||
- **WebSocketShard:** Explicit time out network error handling (#10375) ([a5437a4](https://github.com/discordjs/discord.js/commit/a5437a41f31bf47e9a6f8dc4452086c614d71d1c))
|
||||
|
||||
# [@discordjs/ws@1.1.1](https://github.com/discordjs/discord.js/compare/@discordjs/ws@1.1.0...@discordjs/ws@1.1.1) - (2024-06-02)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- Deno compat (#10271) ([616208b](https://github.com/discordjs/discord.js/commit/616208ba7766ac66a8969ffd2cb7b341fdc2c67b))
|
||||
- Anchor link for events ([0efd1be](https://github.com/discordjs/discord.js/commit/0efd1bea46fa2fc8bcd3dcfd0ac5cd608a0a7df0))
|
||||
- Minify mainlib docs json (#9963) ([4b88306](https://github.com/discordjs/discord.js/commit/4b88306dcb2b16b840ec61e9e33047af3a31c45d))
|
||||
|
||||
## Documentation
|
||||
|
||||
- Remove duplicate word in comment (#10244) ([96169ad](https://github.com/discordjs/discord.js/commit/96169add6d2db37706629c0172692533948a9dca))
|
||||
- Split docs.api.json into multiple json files ([597340f](https://github.com/discordjs/discord.js/commit/597340f288437c35da8c703d9b621274de60d880))
|
||||
- Remove utf-8-validate (#10059) ([7e12bee](https://github.com/discordjs/discord.js/commit/7e12bee337af169bb131d34fa29ed090ebd26c71))
|
||||
|
||||
## Features
|
||||
|
||||
- **ws:** Support for custom worker messaging (#10241) ([728164e](https://github.com/discordjs/discord.js/commit/728164ed868167d43dec7b7e8d11052a37694968))
|
||||
- Local and preview detection ([79fbda3](https://github.com/discordjs/discord.js/commit/79fbda3aac6d4f0f8bfb193e797d09cbe331d315))
|
||||
- Add support for `using` keyword on discord.js `Client` and `WebSocketManager` (#10063) ([543d617](https://github.com/discordjs/discord.js/commit/543d61737e0709b9d88029d01156d48cfcaf3bcc))
|
||||
- Use globally available WebSocket client in runtimes that have it (#10042) ([319ef9a](https://github.com/discordjs/discord.js/commit/319ef9a70b92dbb11726b270ab84e73ca932850f))
|
||||
|
||||
## Refactor
|
||||
|
||||
- Native zlib support (#10243) ([20258f9](https://github.com/discordjs/discord.js/commit/20258f94bf1a62ec1989ef04d839e2800f6e6d28))
|
||||
- **BREAKING CHANGE:** renamed compression related options
|
||||
|
||||
* chore: fix doc comment
|
||||
|
||||
* chore: update debug messages
|
||||
|
||||
* chore: better wording
|
||||
- **Co-authored-by:** Jiralite <33201955+Jiralite@users.noreply.github.com>
|
||||
|
||||
* chore: suggested changes
|
||||
|
||||
* chore: better naming
|
||||
|
||||
* refactor: lazy node:zlib import and lib detection
|
||||
|
||||
* chore: zlib capitalization
|
||||
|
||||
* fix: use proper var
|
||||
|
||||
* refactor: better inflate check
|
||||
- **Co-authored-by:** Aura <kyradiscord@gmail.com>
|
||||
|
||||
* chore: debug label
|
||||
- **Co-authored-by:** Superchupu <53496941+SuperchupuDev@users.noreply.github.com>
|
||||
|
||||
---------
|
||||
- **Co-authored-by:** Jiralite <33201955+Jiralite@users.noreply.github.com>
|
||||
- **Co-authored-by:** Aura <kyradiscord@gmail.com>
|
||||
- **Co-authored-by:** Superchupu <53496941+SuperchupuDev@users.noreply.github.com>
|
||||
- **Co-authored-by:** kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
|
||||
- Docs (#10126) ([18cce83](https://github.com/discordjs/discord.js/commit/18cce83d80598c430218775c53441b6b2ecdc776))
|
||||
- **WebSocketShard:** Payload sending (#10098) ([c878b65](https://github.com/discordjs/discord.js/commit/c878b65ef586cd9b42f765515f87f43cb6165f61))
|
||||
- Use interfaces for AsyncEventEmitter event maps (#10044) ([adfd9cd](https://github.com/discordjs/discord.js/commit/adfd9cd3b32cfabdcc45ec90f535b2852a3ca4a6))
|
||||
|
||||
# [@discordjs/ws@1.1.1](https://github.com/discordjs/discord.js/compare/@discordjs/ws@1.1.0...@discordjs/ws@1.1.1) - (2024-06-02)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
@@ -1,33 +1,58 @@
|
||||
// @ts-nocheck
|
||||
import { setTimeout as sleep } from 'node:timers/promises';
|
||||
import { expect, test, vi } from 'vitest';
|
||||
import * as timers from 'node:timers/promises';
|
||||
import { expect, test, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { SimpleIdentifyThrottler } from '../../src/index.js';
|
||||
|
||||
vi.mock('node:timers/promises', () => ({
|
||||
setTimeout: vi.fn(),
|
||||
}));
|
||||
|
||||
const throttler = new SimpleIdentifyThrottler(2);
|
||||
let throttler: SimpleIdentifyThrottler;
|
||||
const controller = new AbortController();
|
||||
|
||||
vi.useFakeTimers();
|
||||
|
||||
const NOW = vi.fn().mockReturnValue(Date.now());
|
||||
const TIME = Date.now();
|
||||
const NOW = vi.fn().mockReturnValue(TIME);
|
||||
global.Date.now = NOW;
|
||||
|
||||
const sleep = vi.spyOn(timers, 'setTimeout');
|
||||
|
||||
beforeEach(() => {
|
||||
throttler = new SimpleIdentifyThrottler(2);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sleep.mockClear();
|
||||
});
|
||||
|
||||
test('basic case', async () => {
|
||||
// Those shouldn't wait since they're in different keys
|
||||
|
||||
await throttler.waitForIdentify(0);
|
||||
await throttler.waitForIdentify(0, controller.signal);
|
||||
expect(sleep).not.toHaveBeenCalled();
|
||||
|
||||
await throttler.waitForIdentify(1);
|
||||
await throttler.waitForIdentify(1, controller.signal);
|
||||
expect(sleep).not.toHaveBeenCalled();
|
||||
|
||||
// Those should wait
|
||||
|
||||
await throttler.waitForIdentify(2);
|
||||
await throttler.waitForIdentify(2, controller.signal);
|
||||
expect(sleep).toHaveBeenCalledTimes(1);
|
||||
|
||||
await throttler.waitForIdentify(3);
|
||||
await throttler.waitForIdentify(3, controller.signal);
|
||||
expect(sleep).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
test('does not call sleep with a negative time', async () => {
|
||||
await throttler.waitForIdentify(0, controller.signal);
|
||||
expect(sleep).not.toHaveBeenCalled();
|
||||
|
||||
await throttler.waitForIdentify(0, controller.signal);
|
||||
expect(sleep).toHaveBeenCalledTimes(1);
|
||||
|
||||
// By overshooting, we're simulating a bug that existed prior to this test, where-in by enough time
|
||||
// passing before the shard tried to identify for a subsequent time, the passed value would end up being negative
|
||||
// (and this was unchecked). Node simply treats that as 1ms, so it wasn't particularly harmful, but they
|
||||
// recently introduced a warning for it, so we want to avoid that.
|
||||
NOW.mockReturnValueOnce(TIME + 10_000);
|
||||
await throttler.waitForIdentify(0, controller.signal);
|
||||
expect(sleep).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@discordjs/ws",
|
||||
"version": "1.1.1",
|
||||
"version": "1.2.0",
|
||||
"description": "Wrapper around Discord's gateway",
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
@@ -74,34 +74,34 @@
|
||||
"funding": "https://github.com/discordjs/discord.js?sponsor",
|
||||
"dependencies": {
|
||||
"@discordjs/collection": "workspace:^",
|
||||
"@discordjs/rest": "workspace:^",
|
||||
"@discordjs/rest": "^2.4.1",
|
||||
"@discordjs/util": "workspace:^",
|
||||
"@sapphire/async-queue": "^1.5.2",
|
||||
"@types/ws": "^8.5.10",
|
||||
"@vladfrangu/async_event_emitter": "^2.2.4",
|
||||
"discord-api-types": "0.37.83",
|
||||
"discord-api-types": "^0.37.114",
|
||||
"tslib": "^2.6.2",
|
||||
"ws": "^8.16.0"
|
||||
"ws": "^8.17.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@discordjs/api-extractor": "workspace:^",
|
||||
"@discordjs/scripts": "workspace:^",
|
||||
"@favware/cliff-jumper": "^3.0.2",
|
||||
"@favware/cliff-jumper": "^3.0.3",
|
||||
"@types/node": "18.17.9",
|
||||
"@vitest/coverage-v8": "^1.5.0",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"esbuild-plugin-version-injector": "^1.2.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-neon": "^0.1.62",
|
||||
"eslint-formatter-pretty": "^6.0.1",
|
||||
"mock-socket": "^9.3.1",
|
||||
"prettier": "^3.2.5",
|
||||
"tsd": "^0.30.7",
|
||||
"tsup": "^8.0.2",
|
||||
"turbo": "^1.13.2",
|
||||
"prettier": "^3.3.0",
|
||||
"tsd": "^0.31.0",
|
||||
"tsup": "^8.1.0",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5",
|
||||
"undici": "6.13.0",
|
||||
"vitest": "^1.5.0",
|
||||
"undici": "6.18.2",
|
||||
"vitest": "^1.6.0",
|
||||
"zlib-sync": "^0.1.9"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -36,7 +36,7 @@ export class SimpleIdentifyThrottler implements IIdentifyThrottler {
|
||||
|
||||
try {
|
||||
const diff = state.resetsAt - Date.now();
|
||||
if (diff <= 5_000) {
|
||||
if (diff > 0 && diff <= 5_000) {
|
||||
// To account for the latency the IDENTIFY payload goes through, we add a bit more wait time
|
||||
const time = diff + Math.random() * 1_500;
|
||||
await sleep(time);
|
||||
|
||||
@@ -75,3 +75,5 @@ export function getInitialSendRateLimitState(): SendRateLimitState {
|
||||
resetAt: Date.now() + 60_000,
|
||||
};
|
||||
}
|
||||
|
||||
export const KnownNetworkErrorCodes = new Set(['ECONNRESET', 'ECONNREFUSED', 'ETIMEDOUT', 'EAI_AGAIN']);
|
||||
|
||||
@@ -21,9 +21,9 @@ import {
|
||||
type GatewaySendPayload,
|
||||
} from 'discord-api-types/v10';
|
||||
import { WebSocket, type Data } from 'ws';
|
||||
import type { Inflate } from 'zlib-sync';
|
||||
import type { IContextFetchingStrategy } from '../strategies/context/IContextFetchingStrategy.js';
|
||||
import { ImportantGatewayOpcodes, getInitialSendRateLimitState } from '../utils/constants.js';
|
||||
import type * as ZlibSync from 'zlib-sync';
|
||||
import type { IContextFetchingStrategy } from '../strategies/context/IContextFetchingStrategy';
|
||||
import { ImportantGatewayOpcodes, KnownNetworkErrorCodes, getInitialSendRateLimitState } from '../utils/constants.js';
|
||||
import type { SessionInfo } from './WebSocketManager.js';
|
||||
|
||||
// eslint-disable-next-line promise/prefer-await-to-then
|
||||
@@ -88,7 +88,7 @@ export class WebSocketShard extends AsyncEventEmitter<WebSocketShardEventsMap> {
|
||||
|
||||
private useIdentifyCompress = false;
|
||||
|
||||
private inflate: Inflate | null = null;
|
||||
private inflate: ZlibSync.Inflate | null = null;
|
||||
|
||||
private readonly textDecoder = new TextDecoder();
|
||||
|
||||
@@ -107,7 +107,7 @@ export class WebSocketShard extends AsyncEventEmitter<WebSocketShardEventsMap> {
|
||||
// Indicates whether the shard has already resolved its original connect() call
|
||||
private initialConnectResolved = false;
|
||||
|
||||
// Indicates if we failed to connect to the ws url (ECONNREFUSED/ECONNRESET)
|
||||
// Indicates if we failed to connect to the ws url
|
||||
private failedToConnectDueToNetworkError = false;
|
||||
|
||||
private readonly sendQueue = new AsyncQueue();
|
||||
@@ -710,7 +710,7 @@ export class WebSocketShard extends AsyncEventEmitter<WebSocketShardEventsMap> {
|
||||
}
|
||||
|
||||
private onError(error: Error) {
|
||||
if ('code' in error && ['ECONNRESET', 'ECONNREFUSED'].includes(error.code as string)) {
|
||||
if ('code' in error && KnownNetworkErrorCodes.has(error.code as string)) {
|
||||
this.debug(['Failed to connect to the gateway URL specified due to a network error']);
|
||||
this.failedToConnectDueToNetworkError = true;
|
||||
return;
|
||||
@@ -834,15 +834,6 @@ export class WebSocketShard extends AsyncEventEmitter<WebSocketShardEventsMap> {
|
||||
}
|
||||
|
||||
private debug(messages: [string, ...string[]]) {
|
||||
const message = `${messages[0]}${
|
||||
messages.length > 1
|
||||
? `\n${messages
|
||||
.slice(1)
|
||||
.map((m) => ` ${m}`)
|
||||
.join('\n')}`
|
||||
: ''
|
||||
}`;
|
||||
|
||||
this.emit(WebSocketShardEvents.Debug, { message });
|
||||
this.emit(WebSocketShardEvents.Debug, { message: messages.join('\n\t') });
|
||||
}
|
||||
}
|
||||
|
||||
8389
pnpm-lock.yaml
generated
8389
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user