mirror of
https://github.com/discordeno/discordeno.git
synced 2026-05-21 02:40:08 +00:00
Merge branch 'main' of https://github.com/discordeno/discordeno into main
This commit is contained in:
11
.github/CODEOWNERS
vendored
11
.github/CODEOWNERS
vendored
@@ -1 +1,10 @@
|
|||||||
* @Skillz4Killz @itohatweb
|
* @Skillz4Killz @itohatweb
|
||||||
|
|
||||||
|
/.github/workflows/ @H01001000
|
||||||
|
/.github/sync.yml @H01001000
|
||||||
|
/.yarn/ @H01001000
|
||||||
|
/.yarnrc.yml @H01001000
|
||||||
|
/codecov.yml @H01001000
|
||||||
|
/packages/*/package.json @H01001000
|
||||||
|
/package.json @H01001000
|
||||||
|
/turbo.json @H01001000
|
||||||
|
|||||||
82
.github/labeler.yml
vendored
Normal file
82
.github/labeler.yml
vendored
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
version: v1
|
||||||
|
|
||||||
|
labels:
|
||||||
|
- label: 'website'
|
||||||
|
sync: true
|
||||||
|
matcher:
|
||||||
|
files: 'website/**/*'
|
||||||
|
|
||||||
|
- label: 'pkg-all'
|
||||||
|
matcher:
|
||||||
|
files: '*'
|
||||||
|
|
||||||
|
- label: 'pkg-bot'
|
||||||
|
sync: true
|
||||||
|
matcher:
|
||||||
|
files: 'packages/bot/**/*'
|
||||||
|
|
||||||
|
- label: 'pkg-client'
|
||||||
|
sync: true
|
||||||
|
matcher:
|
||||||
|
files: 'packages/client/**/*'
|
||||||
|
|
||||||
|
- label: 'pkg-gateway'
|
||||||
|
sync: true
|
||||||
|
matcher:
|
||||||
|
files: 'packages/gateway/**/*'
|
||||||
|
|
||||||
|
- label: 'pkg-rest'
|
||||||
|
sync: true
|
||||||
|
matcher:
|
||||||
|
files: 'packages/rest/**/*'
|
||||||
|
|
||||||
|
- label: 'pkg-types'
|
||||||
|
sync: true
|
||||||
|
matcher:
|
||||||
|
files: 'packages/types/**/*'
|
||||||
|
|
||||||
|
- label: 'pkg-utils'
|
||||||
|
sync: true
|
||||||
|
matcher:
|
||||||
|
files: 'packages/utils/**/*'
|
||||||
|
|
||||||
|
- label: 't-breaking'
|
||||||
|
matcher:
|
||||||
|
title: "^[a-z]+(\\(.+\\))?!: .*"
|
||||||
|
|
||||||
|
- label: 't-build'
|
||||||
|
matcher:
|
||||||
|
title: "^build(\\(.+\\))?!?: .*"
|
||||||
|
|
||||||
|
- label: 't-ci'
|
||||||
|
matcher:
|
||||||
|
files: '.github/workflows/*'
|
||||||
|
title: '^ci: .*'
|
||||||
|
|
||||||
|
- label: 't-docs'
|
||||||
|
matcher:
|
||||||
|
title: "^docs(\\(.+\\))?!?: .*"
|
||||||
|
|
||||||
|
- label: 't-feat'
|
||||||
|
matcher:
|
||||||
|
title: "^feat(\\(.+\\))?!?: .*"
|
||||||
|
|
||||||
|
- label: 't-fix'
|
||||||
|
matcher:
|
||||||
|
title: "^fix(\\(.+\\))?!?: .*"
|
||||||
|
|
||||||
|
- label: 't-perf'
|
||||||
|
matcher:
|
||||||
|
title: "^perf(\\(.+\\))?!?: .*"
|
||||||
|
|
||||||
|
- label: 't-refactor'
|
||||||
|
matcher:
|
||||||
|
title: "^refactor(\\(.+\\))?!?: .*"
|
||||||
|
|
||||||
|
- label: 't-style'
|
||||||
|
matcher:
|
||||||
|
title: "^refactor(\\(.+\\))?!?: .*"
|
||||||
|
|
||||||
|
- label: 't-test'
|
||||||
|
matcher:
|
||||||
|
title: "^test(\\(.+\\))?!?: .*"
|
||||||
51
.github/workflows/benchmark.yml
vendored
Normal file
51
.github/workflows/benchmark.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
name: Benchmark
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
outputs:
|
||||||
|
cpuMatch:
|
||||||
|
value: ${{ jobs.benchmark.outputs.cpuMatch }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
benchmark:
|
||||||
|
name: Benchmark
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
cpuMatch: ${{ steps.cpuCheck.outputs.match }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 18
|
||||||
|
- name: Check cpu model
|
||||||
|
id: cpuCheck
|
||||||
|
run: node ./scripts/checkCpuModel.js
|
||||||
|
|
||||||
|
- name: Get yarn cache directory path
|
||||||
|
if: ${{ steps.cpuCheck.outputs.match == 'true' }}
|
||||||
|
id: yarn-cache-dir-path
|
||||||
|
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
if: ${{ steps.cpuCheck.outputs.match == 'true' }}
|
||||||
|
with:
|
||||||
|
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||||
|
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-yarn-
|
||||||
|
- run: yarn install --immutable
|
||||||
|
if: ${{ steps.cpuCheck.outputs.match == 'true' }}
|
||||||
|
- name: Build
|
||||||
|
if: ${{ steps.cpuCheck.outputs.match == 'true' }}
|
||||||
|
run: yarn build
|
||||||
|
|
||||||
|
#
|
||||||
|
- name: Download db from benchmark repo
|
||||||
|
if: ${{ steps.cpuCheck.outputs.match == 'true' }}
|
||||||
|
run: wget https://github.com/discordeno/benchmarks/raw/main/db.tar.gz
|
||||||
|
- name: Decompress db
|
||||||
|
if: ${{ steps.cpuCheck.outputs.match == 'true' }}
|
||||||
|
run: tar -xzvf db.tar.gz
|
||||||
|
|
||||||
|
- name: Benchmark
|
||||||
|
if: ${{ steps.cpuCheck.outputs.match == 'true' }}
|
||||||
|
run: node --expose-gc ./packages/benchmark/dist/index.js
|
||||||
147
.github/workflows/bot-test.yml
vendored
147
.github/workflows/bot-test.yml
vendored
@@ -1,147 +0,0 @@
|
|||||||
name: Bot Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
push:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-type-and-test:
|
|
||||||
name: Build Type and Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
|
||||||
- name: Build Type and Test
|
|
||||||
run: yarn build:type --cache-dir=".turbo" --filter=./packages/bot
|
|
||||||
|
|
||||||
build-dist:
|
|
||||||
name: Build Dist
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build-${{ github.sha }}
|
|
||||||
- name: Type Test
|
|
||||||
run: yarn build --cache-dir=".turbo" --filter=./packages/bot
|
|
||||||
|
|
||||||
format-unit-and-integration-test:
|
|
||||||
name: Format Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build-type-and-test
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-lint-${{ github.sha }}
|
|
||||||
- name: Build type cache
|
|
||||||
if: steps.turbo-cache.outputs.cache-hit != 'true'
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
|
||||||
- name: Check Formatting
|
|
||||||
run: yarn lint --cache-dir=".turbo" --filter=./packages/bot
|
|
||||||
|
|
||||||
test-type-unit-and-integration-test:
|
|
||||||
name: Test Type Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build-type-and-test
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-unit-and-integration-test:test-type-${{ github.sha }}
|
|
||||||
- name: Build type cache
|
|
||||||
if: steps.turbo-cache.outputs.cache-hit != 'true'
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
|
||||||
- name: Test Type Test
|
|
||||||
run: yarn test:test-type --cache-dir=".turbo" --filter=./packages/bot
|
|
||||||
|
|
||||||
# Not using matrix because test later on cant needs a specific job
|
|
||||||
bot-unit-test:
|
|
||||||
needs: build-dist
|
|
||||||
uses: ./.github/workflows/unit-test.yml
|
|
||||||
with:
|
|
||||||
package: bot
|
|
||||||
bot-e2e-test:
|
|
||||||
needs: bot-unit-test
|
|
||||||
if: ${{ github.ref == 'refs/heads/main' }}
|
|
||||||
uses: ./.github/workflows/e2e-test.yml
|
|
||||||
secrets: inherit
|
|
||||||
with:
|
|
||||||
package: bot
|
|
||||||
bot-other-runtime-test:
|
|
||||||
needs: bot-unit-test
|
|
||||||
uses: ./.github/workflows/other-runtime-unit-test.yml
|
|
||||||
with:
|
|
||||||
package: bot
|
|
||||||
142
.github/workflows/client-test.yml
vendored
142
.github/workflows/client-test.yml
vendored
@@ -1,142 +0,0 @@
|
|||||||
name: Client Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
push:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-type-and-test:
|
|
||||||
name: Build Type and Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
|
||||||
- name: Build Type and Test
|
|
||||||
run: yarn build:type --cache-dir=".turbo" --filter=./packages/client
|
|
||||||
|
|
||||||
build-dist:
|
|
||||||
name: Build Dist
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build-${{ github.sha }}
|
|
||||||
- name: Type Test
|
|
||||||
run: yarn build --cache-dir=".turbo" --filter=./packages/client
|
|
||||||
|
|
||||||
format-unit-and-integration-test:
|
|
||||||
name: Format Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build-type-and-test
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-lint-${{ github.sha }}
|
|
||||||
- name: Build type cache
|
|
||||||
if: steps.turbo-cache.outputs.cache-hit != 'true'
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
|
||||||
- name: Check Formatting
|
|
||||||
run: yarn lint --cache-dir=".turbo" --filter=./packages/client
|
|
||||||
|
|
||||||
test-type-unit-and-integration-test:
|
|
||||||
name: Test Type Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build-type-and-test
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-unit-and-integration-test:test-type-${{ github.sha }}
|
|
||||||
- name: Build type cache
|
|
||||||
if: steps.turbo-cache.outputs.cache-hit != 'true'
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
|
||||||
- name: Test Type Test
|
|
||||||
run: yarn test:test-type --cache-dir=".turbo" --filter=./packages/client
|
|
||||||
|
|
||||||
# Not using matrix because test later on cant needs a specific job
|
|
||||||
client-unit-test:
|
|
||||||
name: Client
|
|
||||||
needs: build-dist
|
|
||||||
uses: ./.github/workflows/unit-test.yml
|
|
||||||
with:
|
|
||||||
package: client
|
|
||||||
client-other-runtime-test:
|
|
||||||
name: Client
|
|
||||||
needs: client-unit-test
|
|
||||||
uses: ./.github/workflows/other-runtime-unit-test.yml
|
|
||||||
with:
|
|
||||||
package: client
|
|
||||||
142
.github/workflows/discordeno-test.yml
vendored
142
.github/workflows/discordeno-test.yml
vendored
@@ -1,142 +0,0 @@
|
|||||||
name: Discordeno Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
push:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-type-and-test:
|
|
||||||
name: Build Type and Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
|
||||||
- name: Build Type and Test
|
|
||||||
run: yarn build:type --cache-dir=".turbo" --filter=./packages/discordeno
|
|
||||||
|
|
||||||
build-dist:
|
|
||||||
name: Build Dist
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build-${{ github.sha }}
|
|
||||||
- name: Type Test
|
|
||||||
run: yarn build --cache-dir=".turbo" --filter=./packages/discordeno
|
|
||||||
|
|
||||||
format-unit-and-integration-test:
|
|
||||||
name: Format Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build-type-and-test
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-lint-${{ github.sha }}
|
|
||||||
- name: Build type cache
|
|
||||||
if: steps.turbo-cache.outputs.cache-hit != 'true'
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
|
||||||
- name: Check Formatting
|
|
||||||
run: yarn lint --cache-dir=".turbo" --filter=./packages/discordeno
|
|
||||||
|
|
||||||
test-type-unit-and-integration-test:
|
|
||||||
name: Test Type Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build-type-and-test
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-unit-and-integration-test:test-type-${{ github.sha }}
|
|
||||||
- name: Build type cache
|
|
||||||
if: steps.turbo-cache.outputs.cache-hit != 'true'
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
|
||||||
- name: Test Type Test
|
|
||||||
run: yarn test:test-type --cache-dir=".turbo" --filter=./packages/discordeno
|
|
||||||
|
|
||||||
# Not using matrix because test later on cant needs a specific job
|
|
||||||
discordeno-unit-test:
|
|
||||||
name: Discordeno
|
|
||||||
needs: build-dist
|
|
||||||
uses: ./.github/workflows/unit-test.yml
|
|
||||||
with:
|
|
||||||
package: discordeno
|
|
||||||
discordeno-other-runtime-test:
|
|
||||||
name: Discordeno
|
|
||||||
needs: discordeno-unit-test
|
|
||||||
uses: ./.github/workflows/other-runtime-unit-test.yml
|
|
||||||
with:
|
|
||||||
package: discordeno
|
|
||||||
14
.github/workflows/labeler.yml
vendored
Normal file
14
.github/workflows/labeler.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
name: Labeler
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
types: ['edited', 'opened', 'reopened', 'synchronize']
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
labeler:
|
||||||
|
name: Labeler
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: fuxingloh/multi-labeler@v2
|
||||||
|
with:
|
||||||
|
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
name: Gateway Test
|
name: Library Checks
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
push:
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
merge_group:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-type-and-test:
|
build-type-and-test:
|
||||||
@@ -30,7 +33,7 @@ jobs:
|
|||||||
path: .turbo
|
path: .turbo
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
||||||
- name: Build Type and Test
|
- name: Build Type and Test
|
||||||
run: yarn build:type --cache-dir=".turbo" --filter=./packages/gateway
|
run: yarn build:type --cache-dir=".turbo"
|
||||||
|
|
||||||
build-dist:
|
build-dist:
|
||||||
name: Build Dist
|
name: Build Dist
|
||||||
@@ -57,7 +60,7 @@ jobs:
|
|||||||
path: .turbo
|
path: .turbo
|
||||||
key: ${{ runner.os }}-turbo-build-${{ github.sha }}
|
key: ${{ runner.os }}-turbo-build-${{ github.sha }}
|
||||||
- name: Type Test
|
- name: Type Test
|
||||||
run: yarn build --cache-dir=".turbo" --filter=./packages/gateway
|
run: yarn build --cache-dir=".turbo"
|
||||||
|
|
||||||
format-unit-and-integration-test:
|
format-unit-and-integration-test:
|
||||||
name: Format Test
|
name: Format Test
|
||||||
@@ -91,7 +94,7 @@ jobs:
|
|||||||
path: .turbo
|
path: .turbo
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
||||||
- name: Check Formatting
|
- name: Check Formatting
|
||||||
run: yarn lint --cache-dir=".turbo" --filter=./packages/gateway
|
run: yarn lint --cache-dir=".turbo"
|
||||||
|
|
||||||
test-type-unit-and-integration-test:
|
test-type-unit-and-integration-test:
|
||||||
name: Test Type Test
|
name: Test Type Test
|
||||||
@@ -125,9 +128,56 @@ jobs:
|
|||||||
path: .turbo
|
path: .turbo
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
||||||
- name: Test Type Test
|
- name: Test Type Test
|
||||||
run: yarn test:test-type --cache-dir=".turbo" --filter=./packages/gateway
|
run: yarn test:test-type --cache-dir=".turbo"
|
||||||
|
|
||||||
# Not using matrix because test later on cant needs a specific job
|
# Not using matrix because test later on cant needs a specific job
|
||||||
|
bot-unit-test:
|
||||||
|
name: Bot
|
||||||
|
needs: build-dist
|
||||||
|
uses: ./.github/workflows/unit-test.yml
|
||||||
|
with:
|
||||||
|
package: bot
|
||||||
|
bot-e2e-test:
|
||||||
|
name: Bot
|
||||||
|
needs: bot-unit-test
|
||||||
|
if: ${{ github.ref == 'refs/heads/main' || github.event_name == 'merge_group' }}
|
||||||
|
uses: ./.github/workflows/e2e-test.yml
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
package: bot
|
||||||
|
bot-other-runtime-test:
|
||||||
|
name: Bot
|
||||||
|
needs: bot-unit-test
|
||||||
|
uses: ./.github/workflows/other-runtime-unit-test.yml
|
||||||
|
with:
|
||||||
|
package: bot
|
||||||
|
|
||||||
|
client-unit-test:
|
||||||
|
name: Client
|
||||||
|
needs: build-dist
|
||||||
|
uses: ./.github/workflows/unit-test.yml
|
||||||
|
with:
|
||||||
|
package: client
|
||||||
|
client-other-runtime-test:
|
||||||
|
name: Client
|
||||||
|
needs: client-unit-test
|
||||||
|
uses: ./.github/workflows/other-runtime-unit-test.yml
|
||||||
|
with:
|
||||||
|
package: client
|
||||||
|
|
||||||
|
discordeno-unit-test:
|
||||||
|
name: Discordeno
|
||||||
|
needs: build-dist
|
||||||
|
uses: ./.github/workflows/unit-test.yml
|
||||||
|
with:
|
||||||
|
package: discordeno
|
||||||
|
discordeno-other-runtime-test:
|
||||||
|
name: Discordeno
|
||||||
|
needs: discordeno-unit-test
|
||||||
|
uses: ./.github/workflows/other-runtime-unit-test.yml
|
||||||
|
with:
|
||||||
|
package: discordeno
|
||||||
|
|
||||||
gateway-unit-test:
|
gateway-unit-test:
|
||||||
name: Gateway
|
name: Gateway
|
||||||
needs: build-dist
|
needs: build-dist
|
||||||
@@ -146,3 +196,50 @@ jobs:
|
|||||||
uses: ./.github/workflows/other-runtime-unit-test.yml
|
uses: ./.github/workflows/other-runtime-unit-test.yml
|
||||||
with:
|
with:
|
||||||
package: gateway
|
package: gateway
|
||||||
|
|
||||||
|
rest-unit-test:
|
||||||
|
name: Rest
|
||||||
|
needs: build-dist
|
||||||
|
uses: ./.github/workflows/unit-test.yml
|
||||||
|
with:
|
||||||
|
package: rest
|
||||||
|
rest-e2e-test:
|
||||||
|
name: Rest
|
||||||
|
needs: rest-unit-test
|
||||||
|
if: ${{ github.ref == 'refs/heads/main' || github.event_name == 'merge_group' }}
|
||||||
|
uses: ./.github/workflows/e2e-test.yml
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
package: rest
|
||||||
|
rest-other-runtime-test:
|
||||||
|
name: Rest
|
||||||
|
needs: rest-unit-test
|
||||||
|
uses: ./.github/workflows/other-runtime-unit-test.yml
|
||||||
|
with:
|
||||||
|
package: rest
|
||||||
|
|
||||||
|
types-unit-test:
|
||||||
|
name: Types
|
||||||
|
needs: build-dist
|
||||||
|
uses: ./.github/workflows/unit-test.yml
|
||||||
|
with:
|
||||||
|
package: types
|
||||||
|
types-other-runtime-test:
|
||||||
|
name: Types
|
||||||
|
needs: types-unit-test
|
||||||
|
uses: ./.github/workflows/other-runtime-unit-test.yml
|
||||||
|
with:
|
||||||
|
package: types
|
||||||
|
|
||||||
|
utils-unit-test:
|
||||||
|
name: Utils
|
||||||
|
needs: build-dist
|
||||||
|
uses: ./.github/workflows/unit-test.yml
|
||||||
|
with:
|
||||||
|
package: utils
|
||||||
|
utils-other-runtime-test:
|
||||||
|
name: Utils
|
||||||
|
needs: utils-unit-test
|
||||||
|
uses: ./.github/workflows/other-runtime-unit-test.yml
|
||||||
|
with:
|
||||||
|
package: utils
|
||||||
35
.github/workflows/lint.yml
vendored
35
.github/workflows/lint.yml
vendored
@@ -1,35 +0,0 @@
|
|||||||
name: Lint
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
run-linters:
|
|
||||||
name: Run linters
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Check out Git repository
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Run linters
|
|
||||||
uses: wearerequired/lint-action@v2
|
|
||||||
with:
|
|
||||||
auto_fix: true
|
|
||||||
eslint: true
|
|
||||||
eslint_extensions: "js,ts"
|
|
||||||
prettier: true
|
|
||||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
package: ["gateway", "rest", "types", "utils", "bot", "client"]
|
package: ["gateway", "rest", "types", "utils", "bot"]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
|
|||||||
147
.github/workflows/rest-test.yml
vendored
147
.github/workflows/rest-test.yml
vendored
@@ -1,147 +0,0 @@
|
|||||||
name: Rest Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
push:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-type-and-test:
|
|
||||||
name: Build Type and Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
|
||||||
- name: Build Type and Test
|
|
||||||
run: yarn build:type --cache-dir=".turbo" --filter=./packages/rest
|
|
||||||
|
|
||||||
build-dist:
|
|
||||||
name: Build Dist
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build-${{ github.sha }}
|
|
||||||
- name: Type Test
|
|
||||||
run: yarn build --cache-dir=".turbo" --filter=./packages/rest
|
|
||||||
|
|
||||||
format-unit-and-integration-test:
|
|
||||||
name: Format Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build-type-and-test
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-lint-${{ github.sha }}
|
|
||||||
- name: Build type cache
|
|
||||||
if: steps.turbo-cache.outputs.cache-hit != 'true'
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
|
||||||
- name: Check Formatting
|
|
||||||
run: yarn lint --cache-dir=".turbo" --filter=./packages/rest
|
|
||||||
|
|
||||||
test-type-unit-and-integration-test:
|
|
||||||
name: Test Type Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build-type-and-test
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-unit-and-integration-test:test-type-${{ github.sha }}
|
|
||||||
- name: Build type cache
|
|
||||||
if: steps.turbo-cache.outputs.cache-hit != 'true'
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
|
||||||
- name: Test Type Test
|
|
||||||
run: yarn test:test-type --cache-dir=".turbo" --filter=./packages/rest
|
|
||||||
|
|
||||||
# Not using matrix because test later on cant needs a specific job
|
|
||||||
rest-unit-test:
|
|
||||||
needs: build-dist
|
|
||||||
uses: ./.github/workflows/unit-test.yml
|
|
||||||
with:
|
|
||||||
package: rest
|
|
||||||
rest-e2e-test:
|
|
||||||
needs: rest-unit-test
|
|
||||||
if: ${{ github.ref == 'refs/heads/main' }}
|
|
||||||
uses: ./.github/workflows/e2e-test.yml
|
|
||||||
secrets: inherit
|
|
||||||
with:
|
|
||||||
package: rest
|
|
||||||
rest-other-runtime-test:
|
|
||||||
needs: rest-unit-test
|
|
||||||
uses: ./.github/workflows/other-runtime-unit-test.yml
|
|
||||||
with:
|
|
||||||
package: rest
|
|
||||||
56
.github/workflows/retryBenchmark.yml
vendored
Normal file
56
.github/workflows/retryBenchmark.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
name: Benchmark with retry
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
benchmark-try-1:
|
||||||
|
uses: ./.github/workflows/benchmark.yml
|
||||||
|
|
||||||
|
benchmark-try-2:
|
||||||
|
needs: benchmark-try-1
|
||||||
|
if: ${{ needs.benchmark-try-1.outputs.cpuMatch == 'false' }}
|
||||||
|
uses: ./.github/workflows/benchmark.yml
|
||||||
|
|
||||||
|
benchmark-try-3:
|
||||||
|
needs: benchmark-try-2
|
||||||
|
if: ${{ needs.benchmark-try-2.outputs.cpuMatch == 'false' }}
|
||||||
|
uses: ./.github/workflows/benchmark.yml
|
||||||
|
|
||||||
|
benchmark-try-4:
|
||||||
|
needs: benchmark-try-3
|
||||||
|
if: ${{ needs.benchmark-try-3.outputs.cpuMatch == 'false' }}
|
||||||
|
uses: ./.github/workflows/benchmark.yml
|
||||||
|
|
||||||
|
benchmark-try-5:
|
||||||
|
needs: benchmark-try-4
|
||||||
|
if: ${{ needs.benchmark-try-4.outputs.cpuMatch == 'false' }}
|
||||||
|
uses: ./.github/workflows/benchmark.yml
|
||||||
|
|
||||||
|
benchmark-try-6:
|
||||||
|
needs: benchmark-try-5
|
||||||
|
if: ${{ needs.benchmark-try-5.outputs.cpuMatch == 'false' }}
|
||||||
|
uses: ./.github/workflows/benchmark.yml
|
||||||
|
|
||||||
|
benchmark-try-7:
|
||||||
|
needs: benchmark-try-6
|
||||||
|
if: ${{ needs.benchmark-try-6.outputs.cpuMatch == 'false' }}
|
||||||
|
uses: ./.github/workflows/benchmark.yml
|
||||||
|
|
||||||
|
benchmark-try-8:
|
||||||
|
needs: benchmark-try-7
|
||||||
|
if: ${{ needs.benchmark-try-7.outputs.cpuMatch == 'false' }}
|
||||||
|
uses: ./.github/workflows/benchmark.yml
|
||||||
|
|
||||||
|
benchmark-try-9:
|
||||||
|
needs: benchmark-try-8
|
||||||
|
if: ${{ needs.benchmark-try-8.outputs.cpuMatch == 'false' }}
|
||||||
|
uses: ./.github/workflows/benchmark.yml
|
||||||
|
|
||||||
|
benchmark-try-10:
|
||||||
|
needs: benchmark-try-9
|
||||||
|
if: ${{ needs.benchmark-try-9.outputs.cpuMatch == 'false' }}
|
||||||
|
uses: ./.github/workflows/benchmark.yml
|
||||||
142
.github/workflows/types-test.yml
vendored
142
.github/workflows/types-test.yml
vendored
@@ -1,142 +0,0 @@
|
|||||||
name: Types Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
push:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-type-and-test:
|
|
||||||
name: Build Type and Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
|
||||||
- name: Build Type and Test
|
|
||||||
run: yarn build:type --cache-dir=".turbo" --filter=./packages/types
|
|
||||||
|
|
||||||
build-dist:
|
|
||||||
name: Build Dist
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build-${{ github.sha }}
|
|
||||||
- name: Type Test
|
|
||||||
run: yarn build --cache-dir=".turbo" --filter=./packages/types
|
|
||||||
|
|
||||||
format-unit-and-integration-test:
|
|
||||||
name: Format Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build-type-and-test
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-lint-${{ github.sha }}
|
|
||||||
- name: Build type cache
|
|
||||||
if: steps.turbo-cache.outputs.cache-hit != 'true'
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
|
||||||
- name: Check Formatting
|
|
||||||
run: yarn lint --cache-dir=".turbo" --filter=./packages/types
|
|
||||||
|
|
||||||
test-type-unit-and-integration-test:
|
|
||||||
name: Test Type Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build-type-and-test
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-unit-and-integration-test:test-type-${{ github.sha }}
|
|
||||||
- name: Build type cache
|
|
||||||
if: steps.turbo-cache.outputs.cache-hit != 'true'
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
|
||||||
- name: Test Type Test
|
|
||||||
run: yarn test:test-type --cache-dir=".turbo" --filter=./packages/types
|
|
||||||
|
|
||||||
# Not using matrix because test later on cant needs a specific job
|
|
||||||
types-unit-test:
|
|
||||||
name: Types
|
|
||||||
needs: build-dist
|
|
||||||
uses: ./.github/workflows/unit-test.yml
|
|
||||||
with:
|
|
||||||
package: types
|
|
||||||
types-other-runtime-test:
|
|
||||||
name: Types
|
|
||||||
needs: types-unit-test
|
|
||||||
uses: ./.github/workflows/other-runtime-unit-test.yml
|
|
||||||
with:
|
|
||||||
package: types
|
|
||||||
142
.github/workflows/utils-test.yml
vendored
142
.github/workflows/utils-test.yml
vendored
@@ -1,142 +0,0 @@
|
|||||||
name: Utils Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
push:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-type-and-test:
|
|
||||||
name: Build Type and Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
|
||||||
- name: Build Type and Test
|
|
||||||
run: yarn build:type --cache-dir=".turbo" --filter=./packages/utils
|
|
||||||
|
|
||||||
build-dist:
|
|
||||||
name: Build Dist
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build-${{ github.sha }}
|
|
||||||
- name: Type Test
|
|
||||||
run: yarn build --cache-dir=".turbo" --filter=./packages/utils
|
|
||||||
|
|
||||||
format-unit-and-integration-test:
|
|
||||||
name: Format Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build-type-and-test
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-lint-${{ github.sha }}
|
|
||||||
- name: Build type cache
|
|
||||||
if: steps.turbo-cache.outputs.cache-hit != 'true'
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
|
||||||
- name: Check Formatting
|
|
||||||
run: yarn lint --cache-dir=".turbo" --filter=./packages/utils
|
|
||||||
|
|
||||||
test-type-unit-and-integration-test:
|
|
||||||
name: Test Type Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build-type-and-test
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Get yarn cache directory path
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- name: Turbo Cache
|
|
||||||
id: turbo-cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-unit-and-integration-test:test-type-${{ github.sha }}
|
|
||||||
- name: Build type cache
|
|
||||||
if: steps.turbo-cache.outputs.cache-hit != 'true'
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: .turbo
|
|
||||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
|
||||||
- name: Test Type Test
|
|
||||||
run: yarn test:test-type --cache-dir=".turbo" --filter=./packages/utils
|
|
||||||
|
|
||||||
# Not using matrix because test later on cant needs a specific job
|
|
||||||
utils-unit-test:
|
|
||||||
name: Utils
|
|
||||||
needs: build-dist
|
|
||||||
uses: ./.github/workflows/unit-test.yml
|
|
||||||
with:
|
|
||||||
package: utils
|
|
||||||
utils-other-runtime-test:
|
|
||||||
name: Utils
|
|
||||||
needs: utils-unit-test
|
|
||||||
uses: ./.github/workflows/other-runtime-unit-test.yml
|
|
||||||
with:
|
|
||||||
package: utils
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -33,6 +33,7 @@ out
|
|||||||
build
|
build
|
||||||
.docusaurus
|
.docusaurus
|
||||||
.cache-loader
|
.cache-loader
|
||||||
|
/db
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
84
README.md
84
README.md
@@ -6,22 +6,23 @@ Discord API library for [Node.JS](https://nodejs.org), [Deno](https://deno.land)
|
|||||||
|
|
||||||
[](https://discord.com/invite/5vBgXk3UcZ)
|
[](https://discord.com/invite/5vBgXk3UcZ)
|
||||||
[](https://codecov.io/gh/discordeno/discordeno)
|
[](https://codecov.io/gh/discordeno/discordeno)
|
||||||
|

|
||||||
|
|
||||||
## Tips
|
## Tips
|
||||||
|
|
||||||
- If you are already convinced about using Discordeno, go to [Getting Started](https://discordeno.github.io/discordeno/)
|
- If you are already convinced about using Discordeno, go to [Getting Started](https://discordeno.js.org/)
|
||||||
- To learn if Discordeno is right for you, read everything below.
|
- To learn if Discordeno is right for you, read everything below.
|
||||||
|
|
||||||
## Packages
|
## Packages
|
||||||
|
|
||||||
| Package | npm | Tests | Coverage |
|
| Package | npm | Tests |
|
||||||
| ------------------------------------------------------------------------ | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------------------------------------------------------------ | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| [discordeno](https://www.npmjs.com/package/discordeno) |  |  | [](https://codecov.io/gh/discordeno/discordeno) |
|
| [discordeno](https://www.npmjs.com/package/discordeno) |  | [](https://codecov.io/gh/discordeno/discordeno) |
|
||||||
| [@discordeno/types](https://www.npmjs.com/package/@discordeno/types) |  |  | [](https://codecov.io/gh/discordeno/discordeno) |
|
| [@discordeno/types](https://www.npmjs.com/package/@discordeno/types) |  | [](https://codecov.io/gh/discordeno/discordeno) |
|
||||||
| [@discordeno/utils](https://www.npmjs.com/package/@discordeno/utils) |  |  | [](https://codecov.io/gh/discordeno/discordeno) |
|
| [@discordeno/utils](https://www.npmjs.com/package/@discordeno/utils) |  | [](https://codecov.io/gh/discordeno/discordeno) |
|
||||||
| [@discordeno/rest](https://www.npmjs.com/package/@discordeno/rest) |  |  | [](https://codecov.io/gh/discordeno/discordeno) |
|
| [@discordeno/rest](https://www.npmjs.com/package/@discordeno/rest) |  | [](https://codecov.io/gh/discordeno/discordeno) |
|
||||||
| [@discordeno/gateway](https://www.npmjs.com/package/@discordeno/gateway) |  |  | [](https://codecov.io/gh/discordeno/discordeno) |
|
| [@discordeno/gateway](https://www.npmjs.com/package/@discordeno/gateway) |  | [](https://codecov.io/gh/discordeno/discordeno) |
|
||||||
| [@discordeno/bot](https://www.npmjs.com/package/@discordeno/bot) |  |  | [](https://codecov.io/gh/discordeno/discordeno) |
|
| [@discordeno/bot](https://www.npmjs.com/package/@discordeno/bot) |  | [](https://codecov.io/gh/discordeno/discordeno) |
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@@ -29,9 +30,8 @@ Discordeno is actively maintained to guarantee **excellent performance, latest f
|
|||||||
|
|
||||||
- **Simple, Efficient, and Lightweight**: Discordeno is lightweight, simple to use, and adaptable.
|
- **Simple, Efficient, and Lightweight**: Discordeno is lightweight, simple to use, and adaptable.
|
||||||
- By default: No caching.
|
- By default: No caching.
|
||||||
- **Functional & Class API**: Discordeno is flexible enough to provide both methods.
|
- **Functional API**:
|
||||||
- The functional API eliminates the challenges of extending built-in classes and inheritance while ensuring overall simple but performant code.
|
- The functional API eliminates the challenges of extending built-in classes and inheritance while ensuring overall simple but performant code.
|
||||||
- The class based API, client package, provides a similar api as the [Eris](https://github.com/abalabahaha/eris) library to provide the best class based experience.
|
|
||||||
- **Cross Runtime**: Supports the Node.js, Deno, and Bun runtimes.
|
- **Cross Runtime**: Supports the Node.js, Deno, and Bun runtimes.
|
||||||
- **Standalone components**: Discordeno offers the option to have practically any component of a bot as a separate
|
- **Standalone components**: Discordeno offers the option to have practically any component of a bot as a separate
|
||||||
piece, including standalone REST, gateways, custom caches, and more.
|
piece, including standalone REST, gateways, custom caches, and more.
|
||||||
@@ -93,11 +93,69 @@ Have your cache setup in any way you like. Redis, PGSQL or any cache layer you w
|
|||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
Interested? [Check the website](https://discordeno.github.io/discordeno/) for more details on getting started.
|
Interested? [Check the website](https://discordeno.js.org/) for more details on getting started.
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
- [Website](https://discordeno.github.io/discordeno/)
|
- [Website](https://discordeno.js.org/)
|
||||||
- [Discord](https://discord.com/invite/5vBgXk3UcZ)
|
- [Discord](https://discord.com/invite/5vBgXk3UcZ)
|
||||||
|
|
||||||
Discordeno follows [semantic versioning](https://semver.org/)
|
Discordeno follows [semantic versioning](https://semver.org/)
|
||||||
|
|
||||||
|
## Contributing/Developing
|
||||||
|
|
||||||
|
We use yarn as package manager and workspace manager, and turborepo as monorepo manager.
|
||||||
|
|
||||||
|
To config the workspace run
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# if you don't have yarn installed
|
||||||
|
npm install -g yarn
|
||||||
|
|
||||||
|
yarn install
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you can build all the files and types across all packages using
|
||||||
|
(unless specified all commands below are run at root directory)
|
||||||
|
|
||||||
|
```sh
|
||||||
|
yarn release-build
|
||||||
|
```
|
||||||
|
|
||||||
|
You can run unit tests on all packages using
|
||||||
|
|
||||||
|
```sh
|
||||||
|
yarn test:unit
|
||||||
|
```
|
||||||
|
|
||||||
|
Other useful scripts
|
||||||
|
(if you run in the package's directory, you need build dist before for test and types before for lint/fmt. Running in root directory should automatically do it for you)
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# check style
|
||||||
|
yarn lint
|
||||||
|
|
||||||
|
# format code
|
||||||
|
yarn fmt
|
||||||
|
|
||||||
|
# check type
|
||||||
|
yarn test:type
|
||||||
|
|
||||||
|
# check type for tests
|
||||||
|
yarn test:test-type
|
||||||
|
|
||||||
|
# unit test showing coverage
|
||||||
|
yarn test:unit-coverage
|
||||||
|
|
||||||
|
# unit test with Deno
|
||||||
|
yarn test:deno-unit
|
||||||
|
|
||||||
|
# integration test
|
||||||
|
yarn test:integration
|
||||||
|
|
||||||
|
# e2e test
|
||||||
|
yarn test:e2e
|
||||||
|
|
||||||
|
# build doc for website
|
||||||
|
yarn build:doc
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
flags:
|
flags:
|
||||||
client:
|
|
||||||
carryforward: false
|
|
||||||
client-unit:
|
|
||||||
carryforward: false
|
|
||||||
|
|
||||||
discordeno:
|
discordeno:
|
||||||
carryforward: false
|
carryforward: false
|
||||||
discordeno-unit:
|
discordeno-unit:
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
"@discordeno/types": "./packages/types/dist/index.js",
|
"@discordeno/types": "./packages/types/dist/index.js",
|
||||||
"@discordeno/rest": "./packages/rest/dist/index.js",
|
"@discordeno/rest": "./packages/rest/dist/index.js",
|
||||||
"@discordeno/gateway": "./packages/gateway/dist/index.js",
|
"@discordeno/gateway": "./packages/gateway/dist/index.js",
|
||||||
"@discordeno/bot": "./packages/bot/dist/index.js",
|
"@discordeno/bot": "./packages/bot/dist/index.js"
|
||||||
"@discordeno/client": "./packages/client/dist/index.js"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,6 @@
|
|||||||
This repo is meant as a template which you can use to create a Discord bot very easily using the
|
This repo is meant as a template which you can use to create a Discord bot very easily using the
|
||||||
[Discordeno library](https://github.com/discordeno/discordeno).
|
[Discordeno library](https://github.com/discordeno/discordeno).
|
||||||
|
|
||||||
[Website/Guide](https://discordeno.github.io/discordeno//)
|
[Website/Guide](https://discordeno.js.org//)
|
||||||
|
|
||||||
[Discord Server](https://discord.com/invite/5vBgXk3UcZ)
|
[Discord Server](https://discord.com/invite/5vBgXk3UcZ)
|
||||||
|
|||||||
41
packages/benchmark/package.json
Normal file
41
packages/benchmark/package.json
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"name": "benchmark",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"type": "module",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/discordeno/discordeno.git"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build:type": "tsc --declaration --emitDeclarationOnly --declarationDir dist",
|
||||||
|
"release-build": "yarn build && yarn build:type",
|
||||||
|
"fmt": "eslint --fix \"src/**/*.ts*\"",
|
||||||
|
"lint": "eslint \"src/**/*.ts*\"",
|
||||||
|
"build": "swc src --delete-dir-on-start --out-dir dist && node ../../scripts/fixBenchExtension.js",
|
||||||
|
"bench": "node dist/index.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@discordeno/bot": "latest",
|
||||||
|
"@discordeno/gateway": "19.0.0-alpha.1",
|
||||||
|
"@discordeno/rest": "19.0.0-alpha.1",
|
||||||
|
"@discordeno/types": "19.0.0-alpha.1",
|
||||||
|
"@discordeno/utils": "19.0.0-alpha.1",
|
||||||
|
"benchmark": "^2.1.4",
|
||||||
|
"microtime": "^3.1.1",
|
||||||
|
"node-fetch": "^3.3.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@swc/cli": "^0.1.57",
|
||||||
|
"@swc/core": "^1.3.21",
|
||||||
|
"@types/benchmark": "^2",
|
||||||
|
"@types/node": "^18.11.9",
|
||||||
|
"eslint": "^8.0.1",
|
||||||
|
"eslint-config-discordeno": "*",
|
||||||
|
"ts-node": "^10.9.1",
|
||||||
|
"tsconfig": "*",
|
||||||
|
"typescript": "^4.9.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
3
packages/benchmark/src/benchmarkSuite.ts
Normal file
3
packages/benchmark/src/benchmarkSuite.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import Benchmark from 'benchmark'
|
||||||
|
|
||||||
|
export const suite = new Benchmark.Suite()
|
||||||
17
packages/benchmark/src/benchmarks/casting.ts
Normal file
17
packages/benchmark/src/benchmarks/casting.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { camelize, snakelize } from '@discordeno/utils'
|
||||||
|
import { suite } from '../benchmarkSuite.js'
|
||||||
|
import { events } from '../utils/db.js'
|
||||||
|
|
||||||
|
const camelizedEvents: any[] = []
|
||||||
|
|
||||||
|
events.forEach((event) => {
|
||||||
|
camelizedEvents.push(camelize(event))
|
||||||
|
})
|
||||||
|
|
||||||
|
suite.add(`Camelize 1 event`, () => {
|
||||||
|
snakelize(events[1])
|
||||||
|
})
|
||||||
|
|
||||||
|
suite.add(`Snakelize 1 event`, () => {
|
||||||
|
snakelize(camelizedEvents[1])
|
||||||
|
})
|
||||||
37
packages/benchmark/src/benchmarks/memory.ts
Normal file
37
packages/benchmark/src/benchmarks/memory.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { createBot, type Bot } from '@discordeno/bot'
|
||||||
|
import { events as dbEvents } from '../utils/db.js'
|
||||||
|
import { memoryBenchmark } from '../utils/memoryBenchmark.js'
|
||||||
|
|
||||||
|
/* Example Usage
|
||||||
|
deno run --v8-flags="--expose-gc" -A .\index.ts
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
import { createBot } from "https://deno.land/x/discordeno@17.1.0/mod.ts";
|
||||||
|
import { enableCachePlugin } from "https://deno.land/x/discordeno@17.1.0/plugins/mod.ts";
|
||||||
|
memoryBenchmark(() => enableCachePlugin(createBot({
|
||||||
|
token: " ",
|
||||||
|
botId: 0n,
|
||||||
|
})))
|
||||||
|
*/
|
||||||
|
|
||||||
|
const enableCachePlugin = (bot: Bot): Bot => bot
|
||||||
|
|
||||||
|
await memoryBenchmark(
|
||||||
|
'[Cache Plugin]',
|
||||||
|
() =>
|
||||||
|
enableCachePlugin(
|
||||||
|
createBot({
|
||||||
|
token: ' ',
|
||||||
|
events: {},
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
(bot, event) => {
|
||||||
|
// @ts-expect-error it works
|
||||||
|
bot.events[
|
||||||
|
event.payload.t!.toLowerCase().replace(/_([a-z])/g, (g) => {
|
||||||
|
return g[1].toUpperCase()
|
||||||
|
})
|
||||||
|
]?.(event.payload.d, {})
|
||||||
|
},
|
||||||
|
dbEvents.filter((event) => event.payload.t),
|
||||||
|
)
|
||||||
19
packages/benchmark/src/benchmarks/rest.ts
Normal file
19
packages/benchmark/src/benchmarks/rest.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { createRestManager } from '@discordeno/rest'
|
||||||
|
import { suite } from '../benchmarkSuite.js'
|
||||||
|
|
||||||
|
const rest = createRestManager({ token: ' ' })
|
||||||
|
|
||||||
|
suite.add(`rest.simplifyUrl`, () => {
|
||||||
|
rest.simplifyUrl('/messages/555555555555555555', 'PUT')
|
||||||
|
rest.simplifyUrl('/users/555555555555555555', 'PUT')
|
||||||
|
rest.simplifyUrl('/webhooks/555555555555555555', 'PUT')
|
||||||
|
rest.simplifyUrl('/channel/555555555555555555', 'PUT')
|
||||||
|
rest.simplifyUrl('/guild/555555555555555555', 'PUT')
|
||||||
|
rest.simplifyUrl('/channels/555555555555555555', 'PUT')
|
||||||
|
rest.simplifyUrl('/guilds/555555555555555555', 'PUT')
|
||||||
|
rest.simplifyUrl('/channels/555555555555555555/reactions/555555555555555555/wdiubaibfwuabfobaowbfoibnion', 'PUT')
|
||||||
|
rest.simplifyUrl('/channels/555555555555555555/messages/555555555555555555', 'DELETE')
|
||||||
|
rest.simplifyUrl('/channels/555555555555555555/messages/555555555555555555', 'POST')
|
||||||
|
rest.simplifyUrl('/channels/555555555555555555/messages/555555555555555555', 'GET')
|
||||||
|
rest.simplifyUrl('/channels/555555555555555555/messages/555555555555555555', 'PUT')
|
||||||
|
})
|
||||||
12
packages/benchmark/src/index.ts
Normal file
12
packages/benchmark/src/index.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import fs from 'node:fs/promises'
|
||||||
|
import { suite } from './benchmarkSuite.js'
|
||||||
|
|
||||||
|
const benchmarks = await fs.readdir('packages/benchmark/dist/benchmarks').then((files) => files.filter((file) => file.endsWith('.js')))
|
||||||
|
|
||||||
|
await Promise.all(benchmarks.map(async (file) => await import(`./benchmarks/${file}`)))
|
||||||
|
|
||||||
|
suite
|
||||||
|
.on('cycle', function (event: any) {
|
||||||
|
console.log(String(event.target))
|
||||||
|
})
|
||||||
|
.run()
|
||||||
33
packages/benchmark/src/utils/db.ts
Normal file
33
packages/benchmark/src/utils/db.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import type { DiscordGatewayPayload } from '@discordeno/types'
|
||||||
|
import fetch from 'node-fetch'
|
||||||
|
import fs from 'node:fs/promises'
|
||||||
|
|
||||||
|
export const events: Array<{
|
||||||
|
shardId: number
|
||||||
|
payload: DiscordGatewayPayload
|
||||||
|
}> = []
|
||||||
|
|
||||||
|
try {
|
||||||
|
const files = await fs.readdir('db/events')
|
||||||
|
|
||||||
|
for await (const file of files) {
|
||||||
|
const eventsInFile: Array<
|
||||||
|
| {
|
||||||
|
shardId: number
|
||||||
|
payload: DiscordGatewayPayload
|
||||||
|
}
|
||||||
|
| string
|
||||||
|
> = Object.values(await fs.readFile(`db/events/${file}`, 'utf8').then((text) => JSON.parse(text)))
|
||||||
|
eventsInFile.forEach((eventInFile) => {
|
||||||
|
if (typeof eventInFile === 'string') return
|
||||||
|
events.push(eventInFile)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
const event = await fetch('https://raw.githubusercontent.com/discordeno/benchmarks/main/db/events/10.json')
|
||||||
|
.then(async (res) => await res.json())
|
||||||
|
.then((eventsInFile: any) => eventsInFile['0'])
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
events.push(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
157
packages/benchmark/src/utils/memoryBenchmark.ts
Normal file
157
packages/benchmark/src/utils/memoryBenchmark.ts
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
export async function memoryBenchmark<O, E>(
|
||||||
|
name: string,
|
||||||
|
objectCreator: () => O,
|
||||||
|
objectFeeder: (object: O, event: E) => void,
|
||||||
|
events: E[],
|
||||||
|
options: { times: number; log: boolean; table: boolean } = {
|
||||||
|
times: 3,
|
||||||
|
log: false,
|
||||||
|
table: false,
|
||||||
|
},
|
||||||
|
): Promise<void> {
|
||||||
|
const garbageCollect = global.gc ?? (() => {})
|
||||||
|
|
||||||
|
const stages = ['start', 'loaded', 'end', 'cached'] as const
|
||||||
|
const typesOfMemUsages = ['rss', 'heapUsed', 'heapTotal'] as const
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||||
|
async function runTest(object: O) {
|
||||||
|
// Determine memory stats now before touching anything
|
||||||
|
const results: {
|
||||||
|
start: NodeJS.MemoryUsage
|
||||||
|
loaded?: NodeJS.MemoryUsage
|
||||||
|
end?: NodeJS.MemoryUsage
|
||||||
|
cached?: NodeJS.MemoryUsage
|
||||||
|
} = {
|
||||||
|
start: process.memoryUsage(),
|
||||||
|
}
|
||||||
|
garbageCollect()
|
||||||
|
results.start = process.memoryUsage()
|
||||||
|
if (options.log) console.log(`[INFO] Loading json files.`)
|
||||||
|
|
||||||
|
if (options.log) {
|
||||||
|
console.log(`[INFO] DB files loaded into memory.`, events.length)
|
||||||
|
}
|
||||||
|
// Set the memory stats for when files are loaded in.
|
||||||
|
results.loaded = process.memoryUsage()
|
||||||
|
|
||||||
|
events.forEach((event) => {
|
||||||
|
objectFeeder(object, event)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (options.log) {
|
||||||
|
console.log(`[INFO] Processed ${events.length} events.`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set results for data once all events are processed
|
||||||
|
results.end = process.memoryUsage()
|
||||||
|
|
||||||
|
// @ts-expect-error init the object
|
||||||
|
results.cached = {}
|
||||||
|
for (const typeOfMemUsage of typesOfMemUsages) {
|
||||||
|
results.cached![typeOfMemUsage] = results.end[typeOfMemUsage] - results.loaded[typeOfMemUsage]
|
||||||
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
const allResults = {
|
||||||
|
start: {
|
||||||
|
rss: [] as number[],
|
||||||
|
heapUsed: [] as number[],
|
||||||
|
heapTotal: [] as number[],
|
||||||
|
},
|
||||||
|
loaded: {
|
||||||
|
rss: [] as number[],
|
||||||
|
heapUsed: [] as number[],
|
||||||
|
heapTotal: [] as number[],
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
rss: [] as number[],
|
||||||
|
heapUsed: [] as number[],
|
||||||
|
heapTotal: [] as number[],
|
||||||
|
},
|
||||||
|
cached: {
|
||||||
|
rss: [] as number[],
|
||||||
|
heapUsed: [] as number[],
|
||||||
|
heapTotal: [] as number[],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const BYTES = 1000000
|
||||||
|
|
||||||
|
for (let index = 0; index < options.times; index++) {
|
||||||
|
if (options.log) console.log('running the', index + 1, 'time')
|
||||||
|
const currentResult = await runTest(objectCreator())
|
||||||
|
for (const typeOfMemUsage of typesOfMemUsages) {
|
||||||
|
for (const stage of stages) {
|
||||||
|
allResults[stage][typeOfMemUsage].push(currentResult[stage]![typeOfMemUsage])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArrayElement<ArrayType extends readonly unknown[]> = ArrayType extends ReadonlyArray<infer ElementType> ? ElementType : never
|
||||||
|
|
||||||
|
const tableRows = ['Starting', 'Loaded', 'End', 'Cached'] as const
|
||||||
|
const tableFields = ['RSS', 'Heap Used', 'Heap Total'] as const
|
||||||
|
|
||||||
|
const preprocessedResults: {
|
||||||
|
[K in ArrayElement<typeof tableRows>]?: {
|
||||||
|
[K in ArrayElement<typeof tableFields>]?: {
|
||||||
|
value: number
|
||||||
|
min: number
|
||||||
|
max: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} = {}
|
||||||
|
|
||||||
|
for (const [index, tableRow] of tableRows.entries()) {
|
||||||
|
for (const [index2, tableField] of tableFields.entries()) {
|
||||||
|
if (index2 === 0) preprocessedResults[tableRow] = {}
|
||||||
|
preprocessedResults[tableRow]![tableField] = {
|
||||||
|
value:
|
||||||
|
Math.round(
|
||||||
|
(allResults[stages[index]][typesOfMemUsages[index2]].reduce((acc, c) => acc + c, 0) / allResults.start.rss.length / BYTES) * 100,
|
||||||
|
) / 100,
|
||||||
|
min: Math.round((Math.min(...allResults[stages[index]][typesOfMemUsages[index2]]) / BYTES) * 100) / 100,
|
||||||
|
max: Math.round((Math.max(...allResults[stages[index]][typesOfMemUsages[index2]]) / BYTES) * 100) / 100,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const processedResults = preprocessedResults as {
|
||||||
|
[K in ArrayElement<typeof tableRows>]: {
|
||||||
|
[K in ArrayElement<typeof tableFields>]: {
|
||||||
|
value: number
|
||||||
|
min: number
|
||||||
|
max: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const humanReadable: {
|
||||||
|
[K in ArrayElement<typeof tableRows>]?: {
|
||||||
|
[K in ArrayElement<typeof tableFields>]?: string
|
||||||
|
}
|
||||||
|
} = {}
|
||||||
|
|
||||||
|
for (const tableRow of tableRows) {
|
||||||
|
for (const [index, tableField] of tableFields.entries()) {
|
||||||
|
if (index === 0) humanReadable[tableRow] = {}
|
||||||
|
humanReadable[tableRow]![
|
||||||
|
tableField
|
||||||
|
] = `${processedResults[tableRow][tableField].value} MB (${processedResults[tableRow][tableField].min} MB … ${processedResults[tableRow][tableField].max} MB)`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.table) console.table(humanReadable)
|
||||||
|
|
||||||
|
for (const resultKey of Object.keys(processedResults.Cached) as Array<keyof typeof processedResults.Cached>) {
|
||||||
|
const range = Math.max(
|
||||||
|
Math.round((processedResults.Cached[resultKey].min / processedResults.Cached[resultKey].value) * 100) / 100,
|
||||||
|
Math.round((processedResults.Cached[resultKey].max / processedResults.Cached[resultKey].value) * 100) / 100,
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log(`${name} ${resultKey.toString()} x ${processedResults.Cached[resultKey].value} MB ±${isFinite(range) ? range : 0}% (3 runs sampled)`)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -104,8 +104,8 @@ export interface BotInteractionCallbackData {
|
|||||||
embeds?: Embed[]
|
embeds?: Embed[]
|
||||||
/** Allowed mentions for the message */
|
/** Allowed mentions for the message */
|
||||||
allowedMentions?: AllowedMentions
|
allowedMentions?: AllowedMentions
|
||||||
/** The contents of the file being sent */
|
/** The contents of the files being sent */
|
||||||
file?: FileContent | FileContent[]
|
files?: FileContent[]
|
||||||
/** The customId you want to use for this modal response. */
|
/** The customId you want to use for this modal response. */
|
||||||
customId?: string
|
customId?: string
|
||||||
/** The title you want to use for this modal response. */
|
/** The title you want to use for this modal response. */
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"all": true,
|
|
||||||
"src": "src",
|
|
||||||
"reporter": ["text", "lcov"],
|
|
||||||
"include": ["src/**/*.ts"],
|
|
||||||
"exclude": ["tests"]
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"require": "ts-node/register",
|
|
||||||
"loader": "ts-node/esm",
|
|
||||||
"recursive": true,
|
|
||||||
"timeout": 2000,
|
|
||||||
"watch-extensions": "ts",
|
|
||||||
"watch-files": ["src", "tests"],
|
|
||||||
"enable-source-maps": true,
|
|
||||||
"parallel": false
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
# @discordeno/client
|
|
||||||
|
|
||||||
This package is intended to provide a class based implementation on top of discordeno. It is based on Eris libraries API as it is just amazing! This also means since the API is near 1:1 the migration for Eris -> Discordeno is as simple as:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
npm uninstall eris && npm install @discordeno/client
|
|
||||||
```
|
|
||||||
|
|
||||||
Then replace all `from 'eris';` with `from '@discordeno/client'` and enjoy!
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
https://github.com/abalabahaha/eris
|
|
||||||
|
|
||||||
## Eris License
|
|
||||||
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2016-2021 abalabahaha
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
||||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
||||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@discordeno/client",
|
|
||||||
"version": "19.0.0-alpha.1",
|
|
||||||
"main": "./dist/index.js",
|
|
||||||
"types": "./dist/index.d.ts",
|
|
||||||
"type": "module",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/discordeno/discordeno.git"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "swc --delete-dir-on-start src --out-dir dist",
|
|
||||||
"build:type": "tsc --declaration --emitDeclarationOnly --declarationDir dist",
|
|
||||||
"release-build": "yarn build && yarn build:type",
|
|
||||||
"fmt": "eslint --fix \"src/**/*.ts*\"",
|
|
||||||
"lint": "eslint \"src/**/*.ts*\"",
|
|
||||||
"test:unit-coverage": "c8 mocha --no-warnings 'tests/**/*.spec.ts'",
|
|
||||||
"test:unit": "c8 --r lcov mocha --no-warnings 'tests/**/*.spec.ts' && node ../../scripts/coveragePathFixing.js client",
|
|
||||||
"test:deno-unit": "swc tests --delete-dir-on-start --out-dir denoTestsDist && node ../../scripts/fixDenoTestExtension.js && deno test -A --import-map ../../denoImportMap.json denoTestsDist",
|
|
||||||
"test:unit:watch": "mocha --no-warnings --watch --parallel 'tests/**/*.spec.ts'",
|
|
||||||
"test:type": "tsc --noEmit",
|
|
||||||
"test:test-type": "tsc --project tsconfig.test.json"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@discordeno/gateway": "19.0.0-alpha.1",
|
|
||||||
"@discordeno/rest": "19.0.0-alpha.1",
|
|
||||||
"@discordeno/types": "19.0.0-alpha.1",
|
|
||||||
"@discordeno/utils": "19.0.0-alpha.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@swc/cli": "^0.1.62",
|
|
||||||
"@swc/core": "^1.3.40",
|
|
||||||
"@types/chai": "^4.3.4",
|
|
||||||
"@types/mocha": "^10.0.1",
|
|
||||||
"@types/node": "^18.15.3",
|
|
||||||
"@types/sinon": "^10.0.13",
|
|
||||||
"c8": "^7.13.0",
|
|
||||||
"chai": "^4.3.7",
|
|
||||||
"eslint": "^8.36.0",
|
|
||||||
"eslint-config-discordeno": "*",
|
|
||||||
"mocha": "^10.2.0",
|
|
||||||
"sinon": "^15.0.2",
|
|
||||||
"ts-node": "^10.9.1",
|
|
||||||
"tsconfig": "*",
|
|
||||||
"typescript": "^4.9.5"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
import type { BigString } from './Client.js'
|
|
||||||
|
|
||||||
export class Base {
|
|
||||||
/** Internal storage of the id done in bigint to preserve memory */
|
|
||||||
_id: bigint
|
|
||||||
|
|
||||||
constructor(id: BigString) {
|
|
||||||
this._id = BigInt(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The snowflake id */
|
|
||||||
get id(): string {
|
|
||||||
return this._id.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
set id(value: BigString) {
|
|
||||||
this._id = BigInt(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
get createdAt(): number {
|
|
||||||
return Number(this._id / 4194304n + 1420070400000n)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the timestamp in milliseconds associated with a Discord ID/snowflake.
|
|
||||||
* @deprecated Recommend using Object.createdAt or Client.snowflakeToTimestamp if you want to get a timestamp from a id. This is not desired but supported only to keep a similar api to eris.
|
|
||||||
*/
|
|
||||||
static getCreatedAt(id: string): number {
|
|
||||||
return Base.getDiscordEpoch(id) + 1420070400000
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the number of milliseconds since epoch represented by an ID/snowflake
|
|
||||||
* @deprecated Recommend using Object.createdAt or Client.snowflakeToTimestamp if you want to get a timestamp from a id. This is not desired but supported only to keep a similar api to eris.
|
|
||||||
*/
|
|
||||||
static getDiscordEpoch(id: string): number {
|
|
||||||
// @ts-expect-error some eris magic at play here
|
|
||||||
return Math.floor(id / 4194304)
|
|
||||||
}
|
|
||||||
|
|
||||||
toString(): string {
|
|
||||||
return `[${this.constructor.name} ${this.id}]`
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
const json = {
|
|
||||||
id: this.id,
|
|
||||||
createdAt: this.createdAt,
|
|
||||||
}
|
|
||||||
for (const prop of props) {
|
|
||||||
// @ts-expect-error some eris magic at play here
|
|
||||||
const value = this[prop]
|
|
||||||
const type = typeof value
|
|
||||||
if (value === undefined) {
|
|
||||||
continue
|
|
||||||
} else if ((type !== 'object' && type !== 'function' && type !== 'bigint') || value === null) {
|
|
||||||
// @ts-expect-error some eris magic at play here
|
|
||||||
json[prop] = value
|
|
||||||
} else if (value.toJSON !== undefined) {
|
|
||||||
// @ts-expect-error some eris magic at play here
|
|
||||||
json[prop] = value.toJSON()
|
|
||||||
} else if (value.values !== undefined) {
|
|
||||||
// @ts-expect-error some eris magic at play here
|
|
||||||
json[prop] = [...value.values()]
|
|
||||||
} else if (type === 'bigint') {
|
|
||||||
// @ts-expect-error some eris magic at play here
|
|
||||||
json[prop] = value.toString()
|
|
||||||
} else if (type === 'object') {
|
|
||||||
// @ts-expect-error some eris magic at play here
|
|
||||||
json[prop] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return json
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Base
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,140 +0,0 @@
|
|||||||
export class Collection<K, V> extends Map<K, V> {
|
|
||||||
limit: number | undefined
|
|
||||||
|
|
||||||
set(key: K, value: V): this {
|
|
||||||
// When this collection is limitd make sure we can add first
|
|
||||||
if ((this.limit ?? this.limit === 0) && this.size >= this.limit) {
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.set(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
forceSet(key: K, value: V): this {
|
|
||||||
return super.set(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
array(): V[] {
|
|
||||||
return [...this.values()]
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Retrieve the value of the first element in this collection */
|
|
||||||
first(): V | undefined {
|
|
||||||
return this.values().next().value
|
|
||||||
}
|
|
||||||
|
|
||||||
last(): V | undefined {
|
|
||||||
return [...this.values()][this.size - 1]
|
|
||||||
}
|
|
||||||
|
|
||||||
random(): V | undefined {
|
|
||||||
const array = [...this.values()]
|
|
||||||
return array[Math.floor(Math.random() * array.length)]
|
|
||||||
}
|
|
||||||
|
|
||||||
find(callback: (value: V, key: K) => boolean): V | undefined {
|
|
||||||
for (const key of this.keys()) {
|
|
||||||
const value = this.get(key)!
|
|
||||||
if (callback(value, key)) return value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
filter(callback: (value: V, key: K) => boolean, returnArray?: true): V[]
|
|
||||||
filter(callback: (value: V, key: K) => boolean, returnArray: false): Collection<K, V>
|
|
||||||
filter(callback: (value: V, key: K) => boolean, returnArray = true): Collection<K, V> | V[] {
|
|
||||||
const relevant = new Collection<K, V>()
|
|
||||||
this.forEach((value, key) => {
|
|
||||||
if (callback(value, key)) relevant.set(key, value)
|
|
||||||
})
|
|
||||||
|
|
||||||
return returnArray ? relevant.array() : relevant
|
|
||||||
}
|
|
||||||
|
|
||||||
map<T>(callback: (value: V, key: K) => T): T[] {
|
|
||||||
const results = []
|
|
||||||
for (const key of this.keys()) {
|
|
||||||
const value = this.get(key)!
|
|
||||||
results.push(callback(value, key))
|
|
||||||
}
|
|
||||||
return results
|
|
||||||
}
|
|
||||||
|
|
||||||
some(callback: (value: V, key: K) => boolean): boolean {
|
|
||||||
for (const key of this.keys()) {
|
|
||||||
const value = this.get(key)!
|
|
||||||
if (callback(value, key)) return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
every(callback: (value: V, key: K) => boolean): boolean {
|
|
||||||
for (const key of this.keys()) {
|
|
||||||
const value = this.get(key)!
|
|
||||||
if (!callback(value, key)) return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
reduce<T>(callback: (accumulator: T, value: V, key: K) => T, initialValue?: T): T {
|
|
||||||
let accumulator: T = initialValue!
|
|
||||||
|
|
||||||
for (const key of this.keys()) {
|
|
||||||
const value = this.get(key)!
|
|
||||||
accumulator = callback(accumulator, value, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
return accumulator
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a object to the collection.
|
|
||||||
* @deprecated Recommend using Collection.set(). Keeping for the sake of Eris API.
|
|
||||||
* @deprecated extra parameter. No longer used, keeping for sake of Eris API.
|
|
||||||
*/
|
|
||||||
add(obj: V & { id: K }, extra?: unknown, replace?: boolean): V {
|
|
||||||
if (this.limit === 0) return obj
|
|
||||||
|
|
||||||
const existing = this.get(obj.id)
|
|
||||||
if (existing && !replace) {
|
|
||||||
return existing
|
|
||||||
}
|
|
||||||
|
|
||||||
this.set(obj.id, obj)
|
|
||||||
return obj
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(obj: { id: K }): V | undefined {
|
|
||||||
const item = this.get(obj.id)
|
|
||||||
if (!item) return
|
|
||||||
|
|
||||||
this.delete(obj.id)
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
|
|
||||||
update(obj: V & { id: K }, extra?: unknown, replace?: boolean): V {
|
|
||||||
const item = this.get(obj.id)
|
|
||||||
if (!item) {
|
|
||||||
this.set(obj.id, obj)
|
|
||||||
return obj
|
|
||||||
}
|
|
||||||
|
|
||||||
// @ts-expect-error some eris magic at play here
|
|
||||||
item.update?.(obj, extra)
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
|
|
||||||
toRecord(): Record<string, V> {
|
|
||||||
const record: Record<string, V> = {}
|
|
||||||
for (const [key, value] of this.entries()) {
|
|
||||||
// @ts-expect-error should work fine
|
|
||||||
const finalKey = typeof key === 'string' ? key : key.toString()
|
|
||||||
record[finalKey] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
return record
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Collection
|
|
||||||
@@ -1,650 +0,0 @@
|
|||||||
export const GATEWAY_VERSION = 10
|
|
||||||
export const REST_VERSION = 10
|
|
||||||
|
|
||||||
export const MessageFlags = {
|
|
||||||
CROSSPOSTED: 1 << 0,
|
|
||||||
IS_CROSSPOST: 1 << 1,
|
|
||||||
SUPPRESS_EMBEDS: 1 << 2,
|
|
||||||
SOURCE_MESSAGE_DELETED: 1 << 3,
|
|
||||||
URGENT: 1 << 4,
|
|
||||||
HAS_THREAD: 1 << 5,
|
|
||||||
EPHEMERAL: 1 << 6,
|
|
||||||
LOADING: 1 << 7,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ActivityTypes = {
|
|
||||||
GAME: 0,
|
|
||||||
STREAMING: 1,
|
|
||||||
LISTENING: 2,
|
|
||||||
WATCHING: 3,
|
|
||||||
CUSTOM: 4,
|
|
||||||
COMPETING: 5,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ApplicationCommandOptionTypes = {
|
|
||||||
SUB_COMMAND: 1,
|
|
||||||
SUB_COMMAND_GROUP: 2,
|
|
||||||
STRING: 3,
|
|
||||||
INTEGER: 4,
|
|
||||||
BOOLEAN: 5,
|
|
||||||
USER: 6,
|
|
||||||
CHANNEL: 7,
|
|
||||||
ROLE: 8,
|
|
||||||
MENTIONABLE: 9,
|
|
||||||
NUMBER: 10,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ApplicationCommandPermissionTypes = {
|
|
||||||
ROLE: 1,
|
|
||||||
USER: 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ApplicationCommandTypes = {
|
|
||||||
CHAT_INPUT: 1,
|
|
||||||
USER: 2,
|
|
||||||
MESSAGE: 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const AuditLogActions = {
|
|
||||||
GUILD_UPDATE: 1,
|
|
||||||
|
|
||||||
CHANNEL_CREATE: 10,
|
|
||||||
CHANNEL_UPDATE: 11,
|
|
||||||
CHANNEL_DELETE: 12,
|
|
||||||
CHANNEL_OVERWRITE_CREATE: 13,
|
|
||||||
CHANNEL_OVERWRITE_UPDATE: 14,
|
|
||||||
CHANNEL_OVERWRITE_DELETE: 15,
|
|
||||||
|
|
||||||
MEMBER_KICK: 20,
|
|
||||||
MEMBER_PRUNE: 21,
|
|
||||||
MEMBER_BAN_ADD: 22,
|
|
||||||
MEMBER_BAN_REMOVE: 23,
|
|
||||||
MEMBER_UPDATE: 24,
|
|
||||||
MEMBER_ROLE_UPDATE: 25,
|
|
||||||
MEMBER_MOVE: 26,
|
|
||||||
MEMBER_DISCONNECT: 27,
|
|
||||||
BOT_ADD: 28,
|
|
||||||
|
|
||||||
ROLE_CREATE: 30,
|
|
||||||
ROLE_UPDATE: 31,
|
|
||||||
ROLE_DELETE: 32,
|
|
||||||
|
|
||||||
INVITE_CREATE: 40,
|
|
||||||
INVITE_UPDATE: 41,
|
|
||||||
INVITE_DELETE: 42,
|
|
||||||
|
|
||||||
WEBHOOK_CREATE: 50,
|
|
||||||
WEBHOOK_UPDATE: 51,
|
|
||||||
WEBHOOK_DELETE: 52,
|
|
||||||
|
|
||||||
EMOJI_CREATE: 60,
|
|
||||||
EMOJI_UPDATE: 61,
|
|
||||||
EMOJI_DELETE: 62,
|
|
||||||
|
|
||||||
MESSAGE_DELETE: 72,
|
|
||||||
MESSAGE_BULK_DELETE: 73,
|
|
||||||
MESSAGE_PIN: 74,
|
|
||||||
MESSAGE_UNPIN: 75,
|
|
||||||
|
|
||||||
INTEGRATION_CREATE: 80,
|
|
||||||
INTEGRATION_UPDATE: 81,
|
|
||||||
INTEGRATION_DELETE: 82,
|
|
||||||
|
|
||||||
STAGE_INSTANCE_CREATE: 83,
|
|
||||||
STAGE_INSTANCE_UPDATE: 84,
|
|
||||||
STAGE_INSTANCE_DELETE: 85,
|
|
||||||
|
|
||||||
STICKER_CREATE: 90,
|
|
||||||
STICKER_UPDATE: 91,
|
|
||||||
STICKER_DELETE: 92,
|
|
||||||
|
|
||||||
GUILD_SCHEDULED_EVENT_CREATE: 100,
|
|
||||||
GUILD_SCHEDULED_EVENT_UPDATE: 101,
|
|
||||||
GUILD_SCHEDULED_EVENT_DELETE: 102,
|
|
||||||
|
|
||||||
THREAD_CREATE: 110,
|
|
||||||
THREAD_UPDATE: 111,
|
|
||||||
THREAD_DELETE: 112,
|
|
||||||
|
|
||||||
APPLICATION_COMMAND_PERMISSION_UPDATE: 121,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ButtonStyles = {
|
|
||||||
PRIMARY: 1,
|
|
||||||
SECONDARY: 2,
|
|
||||||
SUCCESS: 3,
|
|
||||||
DANGER: 4,
|
|
||||||
LINK: 5,
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum ChannelTypes {
|
|
||||||
GUILD_TEXT = 0,
|
|
||||||
DM = 1,
|
|
||||||
GUILD_VOICE = 2,
|
|
||||||
GROUP_DM = 3,
|
|
||||||
GUILD_CATEGORY = 4,
|
|
||||||
GUILD_NEWS = 5,
|
|
||||||
GUILD_STORE = 6,
|
|
||||||
|
|
||||||
GUILD_NEWS_THREAD = 10,
|
|
||||||
GUILD_PUBLIC_THREAD = 11,
|
|
||||||
GUILD_PRIVATE_THREAD = 12,
|
|
||||||
GUILD_STAGE_VOICE = 13,
|
|
||||||
GUILD_STAGE = 13, // [DEPRECATED]
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ComponentTypes = {
|
|
||||||
ACTION_ROW: 1,
|
|
||||||
BUTTON: 2,
|
|
||||||
SELECT_MENU: 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ConnectionVisibilityTypes = {
|
|
||||||
NONE: 0,
|
|
||||||
EVERYONE: 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const DefaultMessageNotificationLevels = {
|
|
||||||
ALL_MESSAGES: 0,
|
|
||||||
ONLY_MENTIONS: 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ExplicitContentFilterLevels = {
|
|
||||||
DISABLED: 0,
|
|
||||||
MEMBERS_WITHOUT_ROLES: 1,
|
|
||||||
ALL_MEMBERS: 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const GatewayOPCodes = {
|
|
||||||
DISPATCH: 0,
|
|
||||||
EVENT: 0, // [DEPRECATED]
|
|
||||||
HEARTBEAT: 1,
|
|
||||||
IDENTIFY: 2,
|
|
||||||
PRESENCE_UPDATE: 3,
|
|
||||||
STATUS_UPDATE: 3, // [DEPRECATED]
|
|
||||||
VOICE_STATE_UPDATE: 4,
|
|
||||||
VOICE_SERVER_PING: 5,
|
|
||||||
RESUME: 6,
|
|
||||||
RECONNECT: 7,
|
|
||||||
REQUEST_GUILD_MEMBERS: 8,
|
|
||||||
GET_GUILD_MEMBERS: 8, // [DEPRECATED]
|
|
||||||
INVALID_SESSION: 9,
|
|
||||||
HELLO: 10,
|
|
||||||
HEARTBEAT_ACK: 11,
|
|
||||||
SYNC_GUILD: 12,
|
|
||||||
SYNC_CALL: 13,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const GuildFeatures = [
|
|
||||||
'ANIMATED_ICON',
|
|
||||||
'BANNER',
|
|
||||||
'COMMERCE',
|
|
||||||
'COMMUNITY',
|
|
||||||
'CREATOR_MONETIZABLE_PROVISIONAL',
|
|
||||||
'CREATOR_STORE_PAGE',
|
|
||||||
'DISCOVERABLE',
|
|
||||||
'FEATURABLE',
|
|
||||||
'INVITE_SPLASH',
|
|
||||||
'MEMBER_VERIFICATION_GATE_ENABLED',
|
|
||||||
'MORE_STICKERS',
|
|
||||||
'NEWS',
|
|
||||||
'PARTNERED',
|
|
||||||
'PREVIEW_ENABLED',
|
|
||||||
'PRIVATE_THREADS',
|
|
||||||
'ROLE_ICONS',
|
|
||||||
'ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE',
|
|
||||||
'ROLE_SUBSCRIPTIONS_ENABLED',
|
|
||||||
'SEVEN_DAY_THREAD_ARCHIVE',
|
|
||||||
'THREE_DAY_THREAD_ARCHIVE',
|
|
||||||
'TICKETED_EVENTS_ENABLED',
|
|
||||||
'VANITY_URL',
|
|
||||||
'VERIFIED',
|
|
||||||
'VIP_REGIONS',
|
|
||||||
'WELCOME_SCREEN_ENABLED',
|
|
||||||
]
|
|
||||||
|
|
||||||
export const GuildIntegrationExpireBehavior = {
|
|
||||||
REMOVE_ROLE: 0,
|
|
||||||
KICK: 1,
|
|
||||||
}
|
|
||||||
export const GuildIntegrationTypes = ['twitch', 'youtube', 'discord']
|
|
||||||
|
|
||||||
export const GuildNSFWLevels = {
|
|
||||||
DEFAULT: 0,
|
|
||||||
EXPLICIT: 1,
|
|
||||||
SAFE: 2,
|
|
||||||
AGE_RESTRICTED: 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ImageFormats = ['jpg', 'jpeg', 'png', 'webp', 'gif']
|
|
||||||
|
|
||||||
export const ImageSizeBoundaries = {
|
|
||||||
MINIMUM: 16,
|
|
||||||
MAXIMUM: 4096,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Intents = {
|
|
||||||
guilds: 1 << 0,
|
|
||||||
guildMembers: 1 << 1,
|
|
||||||
guildBans: 1 << 2,
|
|
||||||
guildEmojisAndStickers: 1 << 3,
|
|
||||||
guildEmojis: 1 << 3, // [DEPRECATED]
|
|
||||||
guildIntegrations: 1 << 4,
|
|
||||||
guildWebhooks: 1 << 5,
|
|
||||||
guildInvites: 1 << 6,
|
|
||||||
guildVoiceStates: 1 << 7,
|
|
||||||
guildPresences: 1 << 8,
|
|
||||||
guildMessages: 1 << 9,
|
|
||||||
guildMessageReactions: 1 << 10,
|
|
||||||
guildMessageTyping: 1 << 11,
|
|
||||||
directMessages: 1 << 12,
|
|
||||||
directMessageReactions: 1 << 13,
|
|
||||||
directMessageTyping: 1 << 14,
|
|
||||||
|
|
||||||
guildScheduledEvents: 1 << 16,
|
|
||||||
// Override these below
|
|
||||||
allNonPrivileged: 0,
|
|
||||||
allPrivileged: 0,
|
|
||||||
all: 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
Intents.allNonPrivileged =
|
|
||||||
Intents.guilds |
|
|
||||||
Intents.guildBans |
|
|
||||||
Intents.guildEmojisAndStickers |
|
|
||||||
Intents.guildIntegrations |
|
|
||||||
Intents.guildWebhooks |
|
|
||||||
Intents.guildInvites |
|
|
||||||
Intents.guildVoiceStates |
|
|
||||||
Intents.guildMessages |
|
|
||||||
Intents.guildMessageReactions |
|
|
||||||
Intents.guildMessageTyping |
|
|
||||||
Intents.directMessages |
|
|
||||||
Intents.directMessageReactions |
|
|
||||||
Intents.directMessageTyping |
|
|
||||||
Intents.guildScheduledEvents
|
|
||||||
Intents.allPrivileged = Intents.guildMembers | Intents.guildPresences
|
|
||||||
Intents.all = Intents.allNonPrivileged | Intents.allPrivileged
|
|
||||||
|
|
||||||
export const InteractionResponseTypes = {
|
|
||||||
PONG: 1,
|
|
||||||
CHANNEL_MESSAGE_WITH_SOURCE: 4,
|
|
||||||
DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE: 5,
|
|
||||||
DEFERRED_UPDATE_MESSAGE: 6,
|
|
||||||
UPDATE_MESSAGE: 7,
|
|
||||||
APPLICATION_COMMAND_AUTOCOMPLETE_RESULT: 8,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const InteractionTypes = {
|
|
||||||
PING: 1,
|
|
||||||
APPLICATION_COMMAND: 2,
|
|
||||||
MESSAGE_COMPONENT: 3,
|
|
||||||
APPLICATION_COMMAND_AUTOCOMPLETE: 4,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const MFALevels = {
|
|
||||||
NONE: 0,
|
|
||||||
ELEVATED: 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const MessageActivityFlags = {
|
|
||||||
INSTANCE: 1 << 0,
|
|
||||||
JOIN: 1 << 1,
|
|
||||||
SPECTATE: 1 << 2,
|
|
||||||
JOIN_REQUEST: 1 << 3,
|
|
||||||
SYNC: 1 << 4,
|
|
||||||
PLAY: 1 << 5,
|
|
||||||
PARTY_PRIVACY_FRIENDS: 1 << 6,
|
|
||||||
PARTY_PRIVACY_VOICE_CHANNEL: 1 << 7,
|
|
||||||
EMBEDDED: 1 << 8,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const MessageActivityTypes = {
|
|
||||||
JOIN: 1,
|
|
||||||
SPECTATE: 2,
|
|
||||||
LISTEN: 3,
|
|
||||||
JOIN_REQUEST: 5,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const MessageTypes = {
|
|
||||||
DEFAULT: 0,
|
|
||||||
RECIPIENT_ADD: 1,
|
|
||||||
RECIPIENT_REMOVE: 2,
|
|
||||||
CALL: 3,
|
|
||||||
CHANNEL_NAME_CHANGE: 4,
|
|
||||||
CHANNEL_ICON_CHANGE: 5,
|
|
||||||
CHANNEL_PINNED_MESSAGE: 6,
|
|
||||||
GUILD_MEMBER_JOIN: 7,
|
|
||||||
USER_PREMIUM_GUILD_SUBSCRIPTION: 8,
|
|
||||||
USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1: 9,
|
|
||||||
USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2: 10,
|
|
||||||
USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3: 11,
|
|
||||||
CHANNEL_FOLLOW_ADD: 12,
|
|
||||||
|
|
||||||
GUILD_DISCOVERY_DISQUALIFIED: 14,
|
|
||||||
GUILD_DISCOVERY_REQUALIFIED: 15,
|
|
||||||
GUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING: 16,
|
|
||||||
GUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING: 17,
|
|
||||||
THREAD_CREATED: 18,
|
|
||||||
REPLY: 19,
|
|
||||||
CHAT_INPUT_COMMAND: 20,
|
|
||||||
THREAD_STARTER_MESSAGE: 21,
|
|
||||||
GUILD_INVITE_REMINDER: 22,
|
|
||||||
CONTEXT_MENU_COMMAND: 23,
|
|
||||||
AUTO_MODERATION_ACTION: 24,
|
|
||||||
ROLE_SUBSCRIPTION_PURCHASE: 25,
|
|
||||||
INTERACTION_PREMIUM_UPSELL: 26,
|
|
||||||
STAGE_START: 27,
|
|
||||||
STAGE_END: 28,
|
|
||||||
STAGE_SPEAKER: 29,
|
|
||||||
|
|
||||||
STAGE_TOPIC: 31,
|
|
||||||
GUILD_APPLICATION_PREMIUM_SUBSCRIPTION: 32,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const PermissionOverwriteTypes = {
|
|
||||||
ROLE: 0,
|
|
||||||
USER: 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Permissions = {
|
|
||||||
createInstantInvite: 1n << 0n,
|
|
||||||
kickMembers: 1n << 1n,
|
|
||||||
banMembers: 1n << 2n,
|
|
||||||
administrator: 1n << 3n,
|
|
||||||
manageChannels: 1n << 4n,
|
|
||||||
manageGuild: 1n << 5n,
|
|
||||||
addReactions: 1n << 6n,
|
|
||||||
viewAuditLog: 1n << 7n,
|
|
||||||
viewAuditLogs: 1n << 7n, // [DEPRECATED]
|
|
||||||
voicePrioritySpeaker: 1n << 8n,
|
|
||||||
voiceStream: 1n << 9n,
|
|
||||||
stream: 1n << 9n, // [DEPRECATED]
|
|
||||||
viewChannel: 1n << 10n,
|
|
||||||
readMessages: 1n << 10n, // [DEPRECATED]
|
|
||||||
sendMessages: 1n << 11n,
|
|
||||||
sendTTSMessages: 1n << 12n,
|
|
||||||
manageMessages: 1n << 13n,
|
|
||||||
embedLinks: 1n << 14n,
|
|
||||||
attachFiles: 1n << 15n,
|
|
||||||
readMessageHistory: 1n << 16n,
|
|
||||||
mentionEveryone: 1n << 17n,
|
|
||||||
useExternalEmojis: 1n << 18n,
|
|
||||||
externalEmojis: 1n << 18n, // [DEPRECATED]
|
|
||||||
viewGuildInsights: 1n << 19n,
|
|
||||||
voiceConnect: 1n << 20n,
|
|
||||||
voiceSpeak: 1n << 21n,
|
|
||||||
voiceMuteMembers: 1n << 22n,
|
|
||||||
voiceDeafenMembers: 1n << 23n,
|
|
||||||
voiceMoveMembers: 1n << 24n,
|
|
||||||
voiceUseVAD: 1n << 25n,
|
|
||||||
changeNickname: 1n << 26n,
|
|
||||||
manageNicknames: 1n << 27n,
|
|
||||||
manageRoles: 1n << 28n,
|
|
||||||
manageWebhooks: 1n << 29n,
|
|
||||||
manageEmojisAndStickers: 1n << 30n,
|
|
||||||
manageEmojis: 1n << 30n, // [DEPRECATED]
|
|
||||||
useApplicationCommands: 1n << 31n,
|
|
||||||
useSlashCommands: 1n << 31n, // [DEPRECATED]
|
|
||||||
voiceRequestToSpeak: 1n << 32n,
|
|
||||||
manageEvents: 1n << 33n,
|
|
||||||
manageThreads: 1n << 34n,
|
|
||||||
createPublicThreads: 1n << 35n,
|
|
||||||
createPrivateThreads: 1n << 36n,
|
|
||||||
useExternalStickers: 1n << 37n,
|
|
||||||
sendMessagesInThreads: 1n << 38n,
|
|
||||||
startEmbeddedActivities: 1n << 39n,
|
|
||||||
moderateMembers: 1n << 40n,
|
|
||||||
// Override these below
|
|
||||||
all: 0n,
|
|
||||||
allText: 0n,
|
|
||||||
allVoice: 0n,
|
|
||||||
allGuild: 0n,
|
|
||||||
}
|
|
||||||
Permissions.allGuild =
|
|
||||||
Permissions.kickMembers |
|
|
||||||
Permissions.banMembers |
|
|
||||||
Permissions.administrator |
|
|
||||||
Permissions.manageChannels |
|
|
||||||
Permissions.manageGuild |
|
|
||||||
Permissions.viewAuditLog |
|
|
||||||
Permissions.viewGuildInsights |
|
|
||||||
Permissions.changeNickname |
|
|
||||||
Permissions.manageNicknames |
|
|
||||||
Permissions.manageRoles |
|
|
||||||
Permissions.manageWebhooks |
|
|
||||||
Permissions.manageEmojisAndStickers |
|
|
||||||
Permissions.manageEvents |
|
|
||||||
Permissions.moderateMembers
|
|
||||||
Permissions.allText =
|
|
||||||
Permissions.createInstantInvite |
|
|
||||||
Permissions.manageChannels |
|
|
||||||
Permissions.addReactions |
|
|
||||||
Permissions.viewChannel |
|
|
||||||
Permissions.sendMessages |
|
|
||||||
Permissions.sendTTSMessages |
|
|
||||||
Permissions.manageMessages |
|
|
||||||
Permissions.embedLinks |
|
|
||||||
Permissions.attachFiles |
|
|
||||||
Permissions.readMessageHistory |
|
|
||||||
Permissions.mentionEveryone |
|
|
||||||
Permissions.useExternalEmojis |
|
|
||||||
Permissions.manageRoles |
|
|
||||||
Permissions.manageWebhooks |
|
|
||||||
Permissions.useApplicationCommands |
|
|
||||||
Permissions.manageThreads |
|
|
||||||
Permissions.createPublicThreads |
|
|
||||||
Permissions.createPrivateThreads |
|
|
||||||
Permissions.useExternalStickers |
|
|
||||||
Permissions.sendMessagesInThreads
|
|
||||||
Permissions.allVoice =
|
|
||||||
Permissions.createInstantInvite |
|
|
||||||
Permissions.manageChannels |
|
|
||||||
Permissions.voicePrioritySpeaker |
|
|
||||||
Permissions.voiceStream |
|
|
||||||
Permissions.viewChannel |
|
|
||||||
Permissions.voiceConnect |
|
|
||||||
Permissions.voiceSpeak |
|
|
||||||
Permissions.voiceMuteMembers |
|
|
||||||
Permissions.voiceDeafenMembers |
|
|
||||||
Permissions.voiceMoveMembers |
|
|
||||||
Permissions.voiceUseVAD |
|
|
||||||
Permissions.manageRoles |
|
|
||||||
Permissions.voiceRequestToSpeak |
|
|
||||||
Permissions.startEmbeddedActivities
|
|
||||||
Permissions.all = Permissions.allGuild | Permissions.allText | Permissions.allVoice
|
|
||||||
|
|
||||||
export const PremiumTiers = {
|
|
||||||
NONE: 0,
|
|
||||||
TIER_1: 1,
|
|
||||||
TIER_2: 2,
|
|
||||||
TIER_3: 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const GuildScheduledEventStatus = {
|
|
||||||
SCHEDULED: 1,
|
|
||||||
ACTIVE: 2,
|
|
||||||
COMPLETED: 3,
|
|
||||||
CANCELED: 4,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const GuildScheduledEventEntityTypes = {
|
|
||||||
STAGE_INSTANCE: 1,
|
|
||||||
VOICE: 2,
|
|
||||||
EXTERNAL: 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const GuildScheduledEventPrivacyLevel = {
|
|
||||||
PUBLIC: 1,
|
|
||||||
GUILD_ONLY: 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const PremiumTypes = {
|
|
||||||
NONE: 0,
|
|
||||||
NITRO_CLASSIC: 1,
|
|
||||||
NITRO: 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const StageInstancePrivacyLevel = {
|
|
||||||
PUBLIC: 1,
|
|
||||||
GUILD_ONLY: 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const StickerFormats = {
|
|
||||||
PNG: 1,
|
|
||||||
APNG: 2,
|
|
||||||
LOTTIE: 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const StickerTypes = {
|
|
||||||
STANDARD: 1,
|
|
||||||
GUILD: 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const SystemChannelFlags = {
|
|
||||||
SUPPRESS_JOIN_NOTIFICATIONS: 1 << 0,
|
|
||||||
SUPPRESS_PREMIUM_SUBSCRIPTIONS: 1 << 1,
|
|
||||||
SUPPRESS_GUILD_REMINDER_NOTIFICATIONS: 1 << 2,
|
|
||||||
SUPPRESS_JOIN_NOTIFICATION_REPLIES: 1 << 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const SystemJoinMessages = [
|
|
||||||
'%user% joined the party.',
|
|
||||||
'%user% is here.',
|
|
||||||
'Welcome, %user%. We hope you brought pizza.',
|
|
||||||
'A wild %user% appeared.',
|
|
||||||
'%user% just landed.',
|
|
||||||
'%user% just slid into the server.',
|
|
||||||
'%user% just showed up!',
|
|
||||||
'Welcome %user%. Say hi!',
|
|
||||||
'%user% hopped into the server.',
|
|
||||||
'Everyone welcome %user%!',
|
|
||||||
"Glad you're here, %user%.",
|
|
||||||
'Good to see you, %user%.',
|
|
||||||
'Yay you made it, %user%!',
|
|
||||||
]
|
|
||||||
|
|
||||||
export const ThreadMemberFlags = {
|
|
||||||
HAS_INTERACTED: 1 << 0,
|
|
||||||
ALL_MESSAGES: 1 << 1,
|
|
||||||
ONLY_MENTIONS: 1 << 2,
|
|
||||||
NO_MESSAGES: 1 << 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const UserFlags = {
|
|
||||||
NONE: 0,
|
|
||||||
DISCORD_STAFF: 1 << 0,
|
|
||||||
DISCORD_EMPLOYEE: 1 << 0,
|
|
||||||
PARTNER: 1 << 1,
|
|
||||||
PARTNERED_SERVER_OWNER: 1 << 1,
|
|
||||||
DISCORD_PARTNER: 1 << 1, // [DEPRECATED]
|
|
||||||
HYPESQUAD: 1 << 2,
|
|
||||||
HYPESQUAD_EVENTS: 1 << 2,
|
|
||||||
BUG_HUNTER_LEVEL_1: 1 << 3,
|
|
||||||
HOUSE_BRAVERY: 1 << 6,
|
|
||||||
HYPESQUAD_ONLINE_HOUSE_1: 1 << 6,
|
|
||||||
HOUSE_BRILLIANCE: 1 << 7,
|
|
||||||
HYPESQUAD_ONLINE_HOUSE_2: 1 << 7,
|
|
||||||
HOUSE_BALANCE: 1 << 8,
|
|
||||||
HYPESQUAD_ONLINE_HOUSE_3: 1 << 8,
|
|
||||||
PREMIUM_EARLY_SUPPORTER: 1 << 9,
|
|
||||||
EARLY_SUPPORTER: 1 << 9,
|
|
||||||
TEAM_PSEUDO_USER: 1 << 10,
|
|
||||||
TEAM_USER: 1 << 10,
|
|
||||||
SYSTEM: 1 << 12,
|
|
||||||
BUG_HUNTER_LEVEL_2: 1 << 14,
|
|
||||||
VERIFIED_BOT: 1 << 16,
|
|
||||||
VERIFIED_DEVELOPER: 1 << 17,
|
|
||||||
EARLY_VERIFIED_BOT_DEVELOPER: 1 << 17,
|
|
||||||
VERIFIED_BOT_DEVELOPER: 1 << 17,
|
|
||||||
CERTIFIED_MODERATOR: 1 << 18,
|
|
||||||
DISCORD_CERTIFIED_MODERATOR: 1 << 18,
|
|
||||||
BOT_HTTP_INTERACTIONS: 1 << 19,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const VerificationLevels = {
|
|
||||||
NONE: 0,
|
|
||||||
LOW: 1,
|
|
||||||
MEDIUM: 2,
|
|
||||||
HIGH: 3,
|
|
||||||
VERY_HIGH: 4,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const VideoQualityModes = {
|
|
||||||
AUTO: 1,
|
|
||||||
FULL: 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const VoiceOPCodes = {
|
|
||||||
IDENTIFY: 0,
|
|
||||||
SELECT_PROTOCOL: 1,
|
|
||||||
READY: 2,
|
|
||||||
HEARTBEAT: 3,
|
|
||||||
SESSION_DESCRIPTION: 4,
|
|
||||||
SPEAKING: 5,
|
|
||||||
HEARTBEAT_ACK: 6,
|
|
||||||
RESUME: 7,
|
|
||||||
HELLO: 8,
|
|
||||||
RESUMED: 9,
|
|
||||||
CLIENT_DISCONNECT: 13,
|
|
||||||
DISCONNECT: 13, // [DEPRECATED]
|
|
||||||
}
|
|
||||||
|
|
||||||
export const WebhookTypes = {
|
|
||||||
INCOMING: 1,
|
|
||||||
CHANNEL_FOLLOWER: 2,
|
|
||||||
APPLICATION: 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
export type IntentStrings = keyof typeof Intents
|
|
||||||
export type PermissionClientStrings = keyof typeof Permissions
|
|
||||||
|
|
||||||
export const Constants = {
|
|
||||||
GATEWAY_VERSION,
|
|
||||||
REST_VERSION,
|
|
||||||
MessageFlags,
|
|
||||||
ActivityTypes,
|
|
||||||
ApplicationCommandOptionTypes,
|
|
||||||
ApplicationCommandPermissionTypes,
|
|
||||||
ApplicationCommandTypes,
|
|
||||||
AuditLogActions,
|
|
||||||
ButtonStyles,
|
|
||||||
ComponentTypes,
|
|
||||||
ConnectionVisibilityTypes,
|
|
||||||
DefaultMessageNotificationLevels,
|
|
||||||
ExplicitContentFilterLevels,
|
|
||||||
GatewayOPCodes,
|
|
||||||
GuildFeatures,
|
|
||||||
GuildIntegrationExpireBehavior,
|
|
||||||
GuildIntegrationTypes,
|
|
||||||
GuildNSFWLevels,
|
|
||||||
ImageFormats,
|
|
||||||
ImageSizeBoundaries,
|
|
||||||
Intents,
|
|
||||||
InteractionResponseTypes,
|
|
||||||
InteractionTypes,
|
|
||||||
MFALevels,
|
|
||||||
MessageActivityFlags,
|
|
||||||
MessageActivityTypes,
|
|
||||||
MessageTypes,
|
|
||||||
PermissionOverwriteTypes,
|
|
||||||
Permissions,
|
|
||||||
PremiumTiers,
|
|
||||||
GuildScheduledEventStatus,
|
|
||||||
GuildScheduledEventEntityTypes,
|
|
||||||
GuildScheduledEventPrivacyLevel,
|
|
||||||
PremiumTypes,
|
|
||||||
StageInstancePrivacyLevel,
|
|
||||||
StickerFormats,
|
|
||||||
StickerTypes,
|
|
||||||
SystemChannelFlags,
|
|
||||||
SystemJoinMessages,
|
|
||||||
ThreadMemberFlags,
|
|
||||||
UserFlags,
|
|
||||||
VerificationLevels,
|
|
||||||
VideoQualityModes,
|
|
||||||
VoiceOPCodes,
|
|
||||||
WebhookTypes,
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
|
||||||
export type Constants = typeof Constants
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
import type { BigString } from './Client.js'
|
|
||||||
|
|
||||||
export const ORIGINAL_INTERACTION_RESPONSE = (appID: BigString, interactToken: string) => `/webhooks/${appID}/${interactToken}`
|
|
||||||
export const COMMAND = (applicationID: BigString, commandID: BigString) => `/applications/${applicationID}/commands/${commandID}`
|
|
||||||
export const COMMANDS = (applicationID: BigString) => `/applications/${applicationID}/commands`
|
|
||||||
export const COMMAND_PERMISSIONS = (applicationID: BigString, guildID: BigString, commandID: BigString) =>
|
|
||||||
`/applications/${applicationID}/guilds/${guildID}/commands/${commandID}/permissions`
|
|
||||||
export const CHANNEL = (chanID: BigString) => `/channels/${chanID}`
|
|
||||||
export const CHANNEL_BULK_DELETE = (chanID: BigString) => `/channels/${chanID}/messages/bulk-delete`
|
|
||||||
export const CHANNEL_CALL_RING = (chanID: BigString) => `/channels/${chanID}/call/ring`
|
|
||||||
export const CHANNEL_CROSSPOST = (chanID: BigString, msgID: BigString) => `/channels/${chanID}/messages/${msgID}/crosspost`
|
|
||||||
export const CHANNEL_FOLLOW = (chanID: BigString) => `/channels/${chanID}/followers`
|
|
||||||
export const CHANNEL_INVITES = (chanID: BigString) => `/channels/${chanID}/invites`
|
|
||||||
export const CHANNEL_MESSAGE_REACTION = (chanID: BigString, msgID: BigString, reaction: string) =>
|
|
||||||
`/channels/${chanID}/messages/${msgID}/reactions/${reaction}`
|
|
||||||
export const CHANNEL_MESSAGE_REACTION_USER = (chanID: BigString, msgID: BigString, reaction: string, userID: BigString) =>
|
|
||||||
`/channels/${chanID}/messages/${msgID}/reactions/${reaction}/${userID}`
|
|
||||||
export const CHANNEL_MESSAGE_REACTIONS = (chanID: BigString, msgID: BigString) => `/channels/${chanID}/messages/${msgID}/reactions`
|
|
||||||
export const CHANNEL_MESSAGE = (chanID: BigString, msgID: BigString) => `/channels/${chanID}/messages/${msgID}`
|
|
||||||
export const CHANNEL_MESSAGES = (chanID: BigString) => `/channels/${chanID}/messages`
|
|
||||||
export const CHANNEL_MESSAGES_SEARCH = (chanID: BigString) => `/channels/${chanID}/messages/search`
|
|
||||||
export const CHANNEL_PERMISSION = (chanID: BigString, overID: BigString) => `/channels/${chanID}/permissions/${overID}`
|
|
||||||
export const CHANNEL_PERMISSIONS = (chanID: BigString) => `/channels/${chanID}/permissions`
|
|
||||||
export const CHANNEL_PIN = (chanID: BigString, msgID: BigString) => `/channels/${chanID}/pins/${msgID}`
|
|
||||||
export const CHANNEL_PINS = (chanID: BigString) => `/channels/${chanID}/pins`
|
|
||||||
export const CHANNEL_RECIPIENT = (groupID: BigString, userID: BigString) => `/channels/${groupID}/recipients/${userID}`
|
|
||||||
export const CHANNEL_TYPING = (chanID: BigString) => `/channels/${chanID}/typing`
|
|
||||||
export const CHANNEL_WEBHOOKS = (chanID: BigString) => `/channels/${chanID}/webhooks`
|
|
||||||
export const CHANNELS = '/channels'
|
|
||||||
export const CUSTOM_EMOJI_GUILD = (emojiID: BigString) => `/emojis/${emojiID}/guild`
|
|
||||||
export const DISCOVERY_CATEGORIES = '/discovery/categories'
|
|
||||||
export const DISCOVERY_VALIDATION = '/discovery/valid-term'
|
|
||||||
export const GATEWAY = '/gateway'
|
|
||||||
export const GATEWAY_BOT = '/gateway/bot'
|
|
||||||
export const GUILD = (guildID: BigString) => `/guilds/${guildID}`
|
|
||||||
export const GUILD_AUDIT_LOGS = (guildID: BigString) => `/guilds/${guildID}/audit-logs`
|
|
||||||
export const GUILD_BAN = (guildID: BigString, memberID: BigString) => `/guilds/${guildID}/bans/${memberID}`
|
|
||||||
export const GUILD_BANS = (guildID: BigString) => `/guilds/${guildID}/bans`
|
|
||||||
export const GUILD_CHANNELS = (guildID: BigString) => `/guilds/${guildID}/channels`
|
|
||||||
export const GUILD_COMMAND = (applicationID: BigString, guildID: BigString, commandID: BigString) =>
|
|
||||||
`/applications/${applicationID}/guilds/${guildID}/commands/${commandID}`
|
|
||||||
export const GUILD_COMMAND_PERMISSIONS = (applicationID: BigString, guildID: BigString) =>
|
|
||||||
`/applications/${applicationID}/guilds/${guildID}/commands/permissions`
|
|
||||||
export const GUILD_COMMANDS = (applicationID: BigString, guildID: BigString) => `/applications/${applicationID}/guilds/${guildID}/commands`
|
|
||||||
export const GUILD_DISCOVERY = (guildID: BigString) => `/guilds/${guildID}/discovery-metadata`
|
|
||||||
export const GUILD_DISCOVERY_CATEGORY = (guildID: BigString, categoryID: BigString) => `/guilds/${guildID}/discovery-categories/${categoryID}`
|
|
||||||
export const GUILD_EMOJI = (guildID: BigString, emojiID: BigString) => `/guilds/${guildID}/emojis/${emojiID}`
|
|
||||||
export const GUILD_EMOJIS = (guildID: BigString) => `/guilds/${guildID}/emojis`
|
|
||||||
export const GUILD_INTEGRATION = (guildID: BigString, inteID: BigString) => `/guilds/${guildID}/integrations/${inteID}`
|
|
||||||
export const GUILD_INTEGRATION_SYNC = (guildID: BigString, inteID: BigString) => `/guilds/${guildID}/integrations/${inteID}/sync`
|
|
||||||
export const GUILD_INTEGRATIONS = (guildID: BigString) => `/guilds/${guildID}/integrations`
|
|
||||||
export const GUILD_INVITES = (guildID: BigString) => `/guilds/${guildID}/invites`
|
|
||||||
export const GUILD_VANITY_URL = (guildID: BigString) => `/guilds/${guildID}/vanity-url`
|
|
||||||
export const GUILD_MEMBER = (guildID: BigString, memberID: BigString) => `/guilds/${guildID}/members/${memberID}`
|
|
||||||
export const GUILD_MEMBER_NICK = (guildID: BigString, memberID: BigString) => `/guilds/${guildID}/members/${memberID}/nick`
|
|
||||||
export const GUILD_MEMBER_ROLE = (guildID: BigString, memberID: BigString, roleID: BigString) =>
|
|
||||||
`/guilds/${guildID}/members/${memberID}/roles/${roleID}`
|
|
||||||
export const GUILD_MEMBERS = (guildID: BigString) => `/guilds/${guildID}/members`
|
|
||||||
export const GUILD_MEMBERS_SEARCH = (guildID: BigString) => `/guilds/${guildID}/members/search`
|
|
||||||
export const GUILD_MESSAGES_SEARCH = (guildID: BigString) => `/guilds/${guildID}/messages/search`
|
|
||||||
export const GUILD_PREVIEW = (guildID: BigString) => `/guilds/${guildID}/preview`
|
|
||||||
export const GUILD_PRUNE = (guildID: BigString) => `/guilds/${guildID}/prune`
|
|
||||||
export const GUILD_ROLE = (guildID: BigString, roleID: BigString) => `/guilds/${guildID}/roles/${roleID}`
|
|
||||||
export const GUILD_ROLES = (guildID: BigString) => `/guilds/${guildID}/roles`
|
|
||||||
export const GUILD_STICKER = (guildID: BigString, stickerID: BigString) => `/guilds/${guildID}/stickers/${stickerID}`
|
|
||||||
export const GUILD_STICKERS = (guildID: BigString) => `/guilds/${guildID}/stickers`
|
|
||||||
export const GUILD_TEMPLATE = (code: string) => `/guilds/templates/${code}`
|
|
||||||
export const GUILD_TEMPLATES = (guildID: BigString) => `/guilds/${guildID}/templates`
|
|
||||||
export const GUILD_TEMPLATE_GUILD = (guildID: BigString, code: string) => `/guilds/${guildID}/templates/${code}`
|
|
||||||
export const GUILD_VOICE_REGIONS = (guildID: BigString) => `/guilds/${guildID}/regions`
|
|
||||||
export const GUILD_WEBHOOKS = (guildID: BigString) => `/guilds/${guildID}/webhooks`
|
|
||||||
export const GUILD_WELCOME_SCREEN = (guildID: BigString) => `/guilds/${guildID}/welcome-screen`
|
|
||||||
export const GUILD_WIDGET = (guildID: BigString) => `/guilds/${guildID}/widget.json`
|
|
||||||
export const GUILD_WIDGET_SETTINGS = (guildID: BigString) => `/guilds/${guildID}/widget`
|
|
||||||
export const GUILD_VOICE_STATE = (guildID: BigString, user: BigString) => `/guilds/${guildID}/voice-states/${user}`
|
|
||||||
export const GUILDS = '/guilds'
|
|
||||||
export const INTERACTION_RESPOND = (interactID: BigString, interactToken: string) => `/interactions/${interactID}/${interactToken}/callback`
|
|
||||||
export const INVITE = (inviteID: string) => `/invites/${inviteID}`
|
|
||||||
export const OAUTH2_APPLICATION = (appID: BigString) => `/oauth2/applications/${appID}`
|
|
||||||
export const STAGE_INSTANCE = (channelID: BigString) => `/stage-instances/${channelID}`
|
|
||||||
export const STAGE_INSTANCES = '/stage-instances'
|
|
||||||
export const STICKER = (stickerID: BigString) => `/stickers/${stickerID}`
|
|
||||||
export const STICKER_PACKS = '/sticker-packs'
|
|
||||||
export const THREAD_MEMBER = (channelID: BigString, userID: BigString) => `/channels/${channelID}/thread-members/${userID}`
|
|
||||||
export const THREAD_MEMBERS = (channelID: BigString) => `/channels/${channelID}/thread-members`
|
|
||||||
export const THREAD_WITH_MESSAGE = (channelID: BigString, msgID: BigString) => `/channels/${channelID}/messages/${msgID}/threads`
|
|
||||||
export const THREAD_WITHOUT_MESSAGE = (channelID: BigString) => `/channels/${channelID}/threads`
|
|
||||||
export const THREADS_ACTIVE = (channelID: BigString) => `/channels/${channelID}/threads/active`
|
|
||||||
export const THREADS_ARCHIVED = (channelID: BigString, type: string) => `/channels/${channelID}/threads/archived/${type}`
|
|
||||||
export const THREADS_ARCHIVED_JOINED = (channelID: BigString) => `/channels/${channelID}/users/@me/threads/archived/private`
|
|
||||||
export const THREADS_GUILD_ACTIVE = (guildID: BigString) => `/guilds/${guildID}/threads/active`
|
|
||||||
export const USER = (userID: BigString) => `/users/${userID}`
|
|
||||||
export const USER_BILLING = (userID: BigString) => `/users/${userID}/billing`
|
|
||||||
export const USER_BILLING_PAYMENTS = (userID: BigString) => `/users/${userID}/billing/payments`
|
|
||||||
export const USER_BILLING_PREMIUM_SUBSCRIPTION = (userID: BigString) => `/users/${userID}/billing/premium-subscription`
|
|
||||||
export const USER_CHANNELS = (userID: BigString) => `/users/${userID}/channels`
|
|
||||||
export const USER_CONNECTIONS = (userID: BigString) => `/users/${userID}/connections`
|
|
||||||
export const USER_CONNECTION_PLATFORM = (userID: BigString, platform: string, id: string) => `/users/${userID}/connections/${platform}/${id}`
|
|
||||||
export const USER_GUILD = (userID: BigString, guildID: BigString) => `/users/${userID}/guilds/${guildID}`
|
|
||||||
export const USER_GUILDS = (userID: BigString) => `/users/${userID}/guilds`
|
|
||||||
export const USER_MFA_CODES = (userID: BigString) => `/users/${userID}/mfa/codes`
|
|
||||||
export const USER_MFA_TOTP_DISABLE = (userID: BigString) => `/users/${userID}/mfa/totp/disable`
|
|
||||||
export const USER_MFA_TOTP_ENABLE = (userID: BigString) => `/users/${userID}/mfa/totp/enable`
|
|
||||||
export const USER_NOTE = (userID: BigString, targetID: BigString) => `/users/${userID}/note/${targetID}`
|
|
||||||
export const USER_PROFILE = (userID: BigString) => `/users/${userID}/profile`
|
|
||||||
export const USER_RELATIONSHIP = (userID: BigString, relID: BigString) => `/users/${userID}/relationships/${relID}`
|
|
||||||
export const USER_SETTINGS = (userID: BigString) => `/users/${userID}/settings`
|
|
||||||
export const USERS = '/users'
|
|
||||||
export const VOICE_REGIONS = '/voice/regions'
|
|
||||||
export const WEBHOOK = (hookID: BigString) => `/webhooks/${hookID}`
|
|
||||||
export const WEBHOOK_MESSAGE = (hookID: BigString, token: string, msgID: BigString) => `/webhooks/${hookID}/${token}/messages/${msgID}`
|
|
||||||
export const WEBHOOK_SLACK = (hookID: BigString) => `/webhooks/${hookID}/slack`
|
|
||||||
export const WEBHOOK_TOKEN = (hookID: BigString, token: string) => `/webhooks/${hookID}/${token}`
|
|
||||||
export const WEBHOOK_TOKEN_SLACK = (hookID: BigString, token: string) => `/webhooks/${hookID}/${token}/slack`
|
|
||||||
|
|
||||||
// CDN Endpoints
|
|
||||||
export const ACHIEVEMENT_ICON = (applicationID: BigString, achievementID: BigString, icon: string) =>
|
|
||||||
`/app-assets/${applicationID}/achievements/${achievementID}/icons/${icon}`
|
|
||||||
export const APPLICATION_ASSET = (applicationID: BigString, asset: string) => `/app-assets/${applicationID}/${asset}`
|
|
||||||
export const APPLICATION_ICON = (applicationID: BigString, icon: string) => `/app-icons/${applicationID}/${icon}`
|
|
||||||
export const BANNER = (guildOrUserID: BigString, hash: string) => `/banners/${guildOrUserID}/${hash}`
|
|
||||||
export const CHANNEL_ICON = (chanID: BigString, chanIcon: string) => `/channel-icons/${chanID}/${chanIcon}`
|
|
||||||
export const CUSTOM_EMOJI = (emojiID: BigString) => `/emojis/${emojiID}`
|
|
||||||
export const DEFAULT_USER_AVATAR = (userDiscriminator: string) => `/embed/avatars/${userDiscriminator}`
|
|
||||||
export const GUILD_AVATAR = (guildID: BigString, userID: BigString, guildAvatar: string) =>
|
|
||||||
`/guilds/${guildID}/users/${userID}/avatars/${guildAvatar}`
|
|
||||||
export const GUILD_DISCOVERY_SPLASH = (guildID: BigString, guildDiscoverySplash: string) => `/discovery-splashes/${guildID}/${guildDiscoverySplash}`
|
|
||||||
export const GUILD_ICON = (guildID: BigString, guildIcon: string) => `/icons/${guildID}/${guildIcon}`
|
|
||||||
export const GUILD_SPLASH = (guildID: BigString, guildSplash: string) => `/splashes/${guildID}/${guildSplash}`
|
|
||||||
export const ROLE_ICON = (roleID: BigString, roleIcon: string) => `/role-icons/${roleID}/${roleIcon}`
|
|
||||||
export const TEAM_ICON = (teamID: BigString, teamIcon: string) => `/team-icons/${teamID}/${teamIcon}`
|
|
||||||
export const USER_AVATAR = (userID: BigString, userAvatar: string) => `/avatars/${userID}/${userAvatar}`
|
|
||||||
|
|
||||||
// Client Endpoints
|
|
||||||
export const MESSAGE_LINK = (guildID: BigString, channelID: BigString, messageID: BigString) => `/channels/${guildID}/${channelID}/${messageID}`
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
import type { RequestMethods, RestManager } from '@discordeno/rest'
|
|
||||||
import { createRestManager } from '@discordeno/rest'
|
|
||||||
import Base from './Base.js'
|
|
||||||
import type Client from './Client.js'
|
|
||||||
import type { FileContent, RequestHandlerOptions } from './typings.js'
|
|
||||||
|
|
||||||
// TODO: make dynamic based on package.json file
|
|
||||||
const version = '19.0.0-alpha.1'
|
|
||||||
|
|
||||||
export class RequestHandler {
|
|
||||||
/** The client manager. */
|
|
||||||
client: Client
|
|
||||||
/** The options this manager was configured with. */
|
|
||||||
options: RequestHandlerOptions
|
|
||||||
/** The user agent used to make requests. */
|
|
||||||
userAgent: string
|
|
||||||
/** The rate limits currently in cache. */
|
|
||||||
ratelimits: Record<string, unknown>
|
|
||||||
/** The latency information for this manager. */
|
|
||||||
latencyRef: {
|
|
||||||
latency: number
|
|
||||||
raw: number[]
|
|
||||||
timeOffset: number
|
|
||||||
timeOffsets: number[]
|
|
||||||
lastTimeOffsetCheck: number
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether or not the manager is globally blocked. */
|
|
||||||
globalBlock: boolean
|
|
||||||
/** The ready queue */
|
|
||||||
readyQueue: unknown[]
|
|
||||||
/** The internal rest manager from dd. */
|
|
||||||
discordeno: RestManager
|
|
||||||
|
|
||||||
constructor(client: Client, options: RequestHandlerOptions) {
|
|
||||||
this.options = options = Object.assign(
|
|
||||||
{
|
|
||||||
// agent: client.options.agent || null,
|
|
||||||
agent: null,
|
|
||||||
baseURL: 'https://discord.com/api',
|
|
||||||
decodeReasons: true,
|
|
||||||
disableLatencyCompensation: false,
|
|
||||||
domain: 'discord.com',
|
|
||||||
// latencyThreshold: client.options.latencyThreshold || 30000,
|
|
||||||
latencyThreshold: 30000,
|
|
||||||
// ratelimiterOffset: client.options.ratelimiterOffset || 0,
|
|
||||||
ratelimiterOffset: 0,
|
|
||||||
// requestTimeout: client.options.requestTimeout || 15000,
|
|
||||||
requestTimeout: 15000,
|
|
||||||
},
|
|
||||||
options,
|
|
||||||
)
|
|
||||||
|
|
||||||
this.client = client
|
|
||||||
this.discordeno = createRestManager({
|
|
||||||
token: this.client.token,
|
|
||||||
proxy:
|
|
||||||
options.baseURL ?? this.client.options.proxyURL
|
|
||||||
? {
|
|
||||||
baseUrl: options.baseURL ?? this.client.options.proxyURL!,
|
|
||||||
authorization: this.client.token,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
})
|
|
||||||
|
|
||||||
this.userAgent = `DiscordBot (https://github.com/discordeno/discordeno, ${version})`
|
|
||||||
this.ratelimits = {}
|
|
||||||
this.latencyRef = {
|
|
||||||
latency: this.options.ratelimiterOffset ?? 0,
|
|
||||||
raw: new Array(10).fill(this.options.ratelimiterOffset),
|
|
||||||
timeOffset: 0,
|
|
||||||
timeOffsets: new Array(10).fill(0),
|
|
||||||
lastTimeOffsetCheck: 0,
|
|
||||||
}
|
|
||||||
this.globalBlock = false
|
|
||||||
this.readyQueue = []
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use `.client` instead
|
|
||||||
*/
|
|
||||||
get _client(): Client {
|
|
||||||
return this.client
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Useless, handled by discordeno itself. Kept for Eris api compatibility.
|
|
||||||
*/
|
|
||||||
globalUnblock(): void {}
|
|
||||||
|
|
||||||
warnUser(): void {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make an API request
|
|
||||||
* @deprecated Use a proxy rest instead.
|
|
||||||
*/
|
|
||||||
async request(method: RequestMethods, url: string, auth?: boolean, body?: any, file?: FileContent): Promise<unknown> {
|
|
||||||
if (file) body.file = file
|
|
||||||
|
|
||||||
return await this.discordeno.makeRequest(method, url, body)
|
|
||||||
}
|
|
||||||
|
|
||||||
routefy(url: string, method: RequestMethods): string {
|
|
||||||
return this.discordeno.simplifyUrl(url, method)
|
|
||||||
}
|
|
||||||
|
|
||||||
toString(): string {
|
|
||||||
return '[RequestHandler]'
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return Base.prototype.toJSON.call(this, ['globalBlock', 'latencyRef', 'options', 'ratelimits', 'readyQueue', 'userAgent', ...props])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default RequestHandler
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
/* eslint-disable no-useless-call */
|
|
||||||
|
|
||||||
import type { DiscordInvite, DiscordInviteCreate, DiscordMemberWithUser, TargetTypes } from '@discordeno/types'
|
|
||||||
import Base from '../Base.js'
|
|
||||||
import type Client from '../Client.js'
|
|
||||||
import type Channel from './channels/Channel.js'
|
|
||||||
import Guild from './guilds/Guild.js'
|
|
||||||
import Member from './guilds/Member.js'
|
|
||||||
import User from './users/User.js'
|
|
||||||
|
|
||||||
export class Invite {
|
|
||||||
/** The client object. */
|
|
||||||
client: Client
|
|
||||||
/** The invite code (unique Id) */
|
|
||||||
code: string
|
|
||||||
/** The channel this invite is for */
|
|
||||||
channel?: Channel
|
|
||||||
/** The guild this invite is for. */
|
|
||||||
guild?: Guild
|
|
||||||
/** The user who created this invite. */
|
|
||||||
inviter?: User
|
|
||||||
/** The amount of times this invite has been used. */
|
|
||||||
uses: number | null = null
|
|
||||||
/** The amount of times this invite can be used. */
|
|
||||||
maxUses: number | null = null
|
|
||||||
/** How long the invite is valid for (in seconds) */
|
|
||||||
maxAge: number | null = null
|
|
||||||
/** Whether or not the invite is temporary (invited users will be kicked on disconnect unless they're assigned a role) */
|
|
||||||
temporary: boolean = false
|
|
||||||
/** The time at which the invite was created */
|
|
||||||
createdAt?: number
|
|
||||||
|
|
||||||
presenceCount?: number | null
|
|
||||||
memberCount?: number | null
|
|
||||||
|
|
||||||
stageInstance?: {
|
|
||||||
members: Member[]
|
|
||||||
participantCount: number
|
|
||||||
speakerCount: number
|
|
||||||
topic: string
|
|
||||||
} | null
|
|
||||||
|
|
||||||
targetApplicationID?: string | null
|
|
||||||
targetType?: TargetTypes | null
|
|
||||||
targetUser?: User | null
|
|
||||||
|
|
||||||
constructor(data: DiscordInvite | DiscordInviteCreate, client: Client) {
|
|
||||||
// super();
|
|
||||||
this.client = client
|
|
||||||
this.code = data.code
|
|
||||||
// @ts-expect-error js hacks
|
|
||||||
this.channel = data.channel
|
|
||||||
|
|
||||||
if (data.inviter) {
|
|
||||||
this.inviter = new User(data.inviter, client)
|
|
||||||
client.users.set(this.inviter.id, this.inviter)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isInviteCreate(data)) {
|
|
||||||
this.uses = data.uses !== undefined ? data.uses : null
|
|
||||||
this.maxUses = data.max_uses !== undefined ? data.max_uses : null
|
|
||||||
this.maxAge = data.max_age !== undefined ? data.max_age : null
|
|
||||||
this.temporary = data.temporary !== undefined ? data.temporary : false
|
|
||||||
this.createdAt = Date.parse(data.created_at)
|
|
||||||
} else {
|
|
||||||
if (data.guild) {
|
|
||||||
if (client.guilds.has(data.guild.id!)) {
|
|
||||||
if (data.channel) {
|
|
||||||
// @ts-expect-error should work i think dumb partials
|
|
||||||
const channel = new GuildChannel(data.channel, client)
|
|
||||||
client.guilds.get(data.guild.id!)?.channels.set(channel.id, channel)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// @ts-expect-error js hacks
|
|
||||||
this.guild = new Guild(data.guild, client)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.presenceCount = data.approximate_presence_count !== undefined ? data.approximate_presence_count : null
|
|
||||||
this.memberCount = data.approximate_member_count !== undefined ? data.approximate_member_count : null
|
|
||||||
if (data.stage_instance !== undefined) {
|
|
||||||
this.stageInstance = {
|
|
||||||
members: data.stage_instance.members.map((m) => {
|
|
||||||
// @ts-expect-error js hacks
|
|
||||||
const member = new Member(m as DiscordMemberWithUser, this.guild, client)
|
|
||||||
this.guild?.members.set(member.id, member)
|
|
||||||
return member
|
|
||||||
}),
|
|
||||||
participantCount: data.stage_instance.participant_count,
|
|
||||||
speakerCount: data.stage_instance.speaker_count,
|
|
||||||
topic: data.stage_instance.topic,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.stageInstance = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.targetApplicationID = data.target_application !== undefined ? data.target_application.id : null
|
|
||||||
this.targetType = data.target_type !== undefined ? data.target_type : null
|
|
||||||
this.targetUser = data.target_user !== undefined ? new User(data.target_user, client) : null
|
|
||||||
if (this.targetUser) client.users.set(this.targetUser.id, this.targetUser)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use .client
|
|
||||||
*/
|
|
||||||
get _client(): Client {
|
|
||||||
return this.client
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use .createdAt
|
|
||||||
*/
|
|
||||||
get _createdAt(): number | undefined {
|
|
||||||
return this.createdAt
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete the invite */
|
|
||||||
async delete(reason?: string): Promise<void> {
|
|
||||||
return await this.client.deleteInvite.call(this.client, this.code, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
toString(): string {
|
|
||||||
return `[Invite ${this.code}]`
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props = []): Record<string, any> {
|
|
||||||
return Base.prototype.toJSON([
|
|
||||||
'channel',
|
|
||||||
'code',
|
|
||||||
'createdAt',
|
|
||||||
'guild',
|
|
||||||
'maxAge',
|
|
||||||
'maxUses',
|
|
||||||
'memberCount',
|
|
||||||
'presenceCount',
|
|
||||||
'revoked',
|
|
||||||
'temporary',
|
|
||||||
'uses',
|
|
||||||
...props,
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
isInviteCreate(data: DiscordInvite | DiscordInviteCreate): data is DiscordInviteCreate {
|
|
||||||
return Reflect.has(data, 'created_at')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Invite
|
|
||||||
@@ -1,444 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
|
||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
/* eslint-disable no-useless-call */
|
|
||||||
|
|
||||||
import {
|
|
||||||
MessageTypes,
|
|
||||||
type DiscordApplication,
|
|
||||||
type DiscordAttachment,
|
|
||||||
type DiscordEmbed,
|
|
||||||
type DiscordMemberWithUser,
|
|
||||||
type DiscordMessage,
|
|
||||||
type DiscordMessageActivity,
|
|
||||||
type DiscordMessageComponents,
|
|
||||||
type DiscordStickerItem,
|
|
||||||
type InteractionTypes,
|
|
||||||
} from '@discordeno/types'
|
|
||||||
import Base from '../Base.js'
|
|
||||||
import type Client from '../Client.js'
|
|
||||||
import { MessageFlags } from '../Constants.js'
|
|
||||||
import { MESSAGE_LINK } from '../Endpoints.js'
|
|
||||||
import type { GetMessageReactionOptions, MessageContentEdit, MessageWebhookContent } from '../typings.js'
|
|
||||||
import type NewsChannel from './channels/News.js'
|
|
||||||
import type PrivateChannel from './channels/Private.js'
|
|
||||||
import type TextChannel from './channels/Text.js'
|
|
||||||
import type TextVoiceChannel from './channels/TextVoice.js'
|
|
||||||
import type NewsThreadChannel from './channels/threads/NewsThread.js'
|
|
||||||
import type PrivateThreadChannel from './channels/threads/PrivateThread.js'
|
|
||||||
import type PublicThreadChannel from './channels/threads/PublicThread.js'
|
|
||||||
import type Guild from './guilds/Guild.js'
|
|
||||||
import Member from './guilds/Member.js'
|
|
||||||
import User from './users/User.js'
|
|
||||||
|
|
||||||
export class Message extends Base {
|
|
||||||
/** The client manager. */
|
|
||||||
client: Client
|
|
||||||
/** Timestamp of message creation */
|
|
||||||
timestamp: number
|
|
||||||
/** The type of the message */
|
|
||||||
type: MessageTypes
|
|
||||||
/** The channel the message is in. Can be partial with only the id if the channel is not cached. */
|
|
||||||
channel: PrivateChannel | TextChannel | NewsChannel | NewsThreadChannel | PublicThreadChannel | PrivateThreadChannel | TextVoiceChannel
|
|
||||||
/** The message content. */
|
|
||||||
content: string
|
|
||||||
/** An object containing the reactions on the message. Each key is a reaction emoji and each value is an object with properties `me` (Boolean) and `count` (Number) for that specific reaction emoji. */
|
|
||||||
reactions: Record<string, { me: boolean; count: number }>
|
|
||||||
/** The ID of the guild this message is in (undefined if in DMs) */
|
|
||||||
guildID?: string
|
|
||||||
/** ID of the webhook that sent the message */
|
|
||||||
webhookID?: string
|
|
||||||
/** An object containing the reference to the original message if it is a crossposted message or reply */
|
|
||||||
messageReference?: {
|
|
||||||
/** The id of the original message this message was crossposted from */
|
|
||||||
messageID?: string
|
|
||||||
/** The id of the channel this message was crossposted from */
|
|
||||||
channelID?: string
|
|
||||||
/** The id of the guild this message was crossposted from */
|
|
||||||
guildID?: string
|
|
||||||
} | null
|
|
||||||
|
|
||||||
/** The flags that are enabled on this message. */
|
|
||||||
flags: number
|
|
||||||
/** The message author */
|
|
||||||
author: User
|
|
||||||
/** The message author with server-specific data */
|
|
||||||
member?: Member
|
|
||||||
/** The message that was replied to. If undefined, message data was not received. If null, the message was deleted. */
|
|
||||||
referencedMessage?: Message | null
|
|
||||||
/** An object containing info about the interaction the message is responding to, if applicable */
|
|
||||||
interaction?: {
|
|
||||||
/** The id of the interaction */
|
|
||||||
id: string
|
|
||||||
/** The type of interaction */
|
|
||||||
type: InteractionTypes
|
|
||||||
/** The name of the command */
|
|
||||||
name: string
|
|
||||||
/** The user who invoked the interaction */
|
|
||||||
user: User
|
|
||||||
/** The member who invoked the interaction */
|
|
||||||
member?: Member
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Array of mentioned users */
|
|
||||||
mentions: User[] = []
|
|
||||||
/** Array of mentioned roles' ids */
|
|
||||||
roleMentions: string[] = []
|
|
||||||
/** Array of attachments */
|
|
||||||
attachments: DiscordAttachment[] = []
|
|
||||||
/** Array of embeds */
|
|
||||||
embeds: DiscordEmbed[] = []
|
|
||||||
/** The stickers sent with the message */
|
|
||||||
stickerItems: DiscordStickerItem[] = []
|
|
||||||
/** An array of component objects */
|
|
||||||
components: DiscordMessageComponents = []
|
|
||||||
/** The activity specified in the message */
|
|
||||||
activity?: DiscordMessageActivity
|
|
||||||
/** The application of the activity in the message */
|
|
||||||
application?: Partial<DiscordApplication>
|
|
||||||
/** The ID of the interaction's application */
|
|
||||||
applicationID?: string
|
|
||||||
/** Timestamp of latest message edit */
|
|
||||||
editedTimestamp?: number
|
|
||||||
/** Whether the message mentions everyone/here or not */
|
|
||||||
mentionEveryone: boolean = false
|
|
||||||
/** Whether the message is pinned or not */
|
|
||||||
pinned: boolean = false
|
|
||||||
/** Whether to play the message using TTS or not */
|
|
||||||
tts: boolean = false
|
|
||||||
|
|
||||||
constructor(data: DiscordMessage, client: Client) {
|
|
||||||
super(data.id)
|
|
||||||
|
|
||||||
this.client = client
|
|
||||||
this.timestamp = Date.parse(data.timestamp)
|
|
||||||
|
|
||||||
this.type = data.type || MessageTypes.Default
|
|
||||||
this.timestamp = Date.parse(data.timestamp)
|
|
||||||
// @ts-expect-error eris js hack
|
|
||||||
this.channel = this.client.getChannel(data.channel_id) ?? {
|
|
||||||
id: data.channel_id,
|
|
||||||
}
|
|
||||||
this.content = ''
|
|
||||||
this.reactions = {}
|
|
||||||
this.guildID = data.guild_id
|
|
||||||
this.webhookID = data.webhook_id
|
|
||||||
|
|
||||||
if (data.message_reference) {
|
|
||||||
this.messageReference = {
|
|
||||||
messageID: data.message_reference.message_id,
|
|
||||||
channelID: data.message_reference.channel_id,
|
|
||||||
guildID: data.message_reference.guild_id,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.messageReference = null
|
|
||||||
}
|
|
||||||
|
|
||||||
this.flags = data.flags ?? 0
|
|
||||||
|
|
||||||
this.author = new User(data.author, client)
|
|
||||||
if (!data.webhook_id) {
|
|
||||||
this.client.users.set(this.author.id, this.author)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.referenced_message) {
|
|
||||||
const channel = this.client.getChannel(data.referenced_message.channel_id) as TextChannel
|
|
||||||
this.referencedMessage = new Message(data.referenced_message, this.client)
|
|
||||||
|
|
||||||
if (channel) {
|
|
||||||
channel.messages.set(this.referencedMessage.id, this.referencedMessage)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.referencedMessage = data.referenced_message
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.interaction) {
|
|
||||||
this.interaction = {
|
|
||||||
id: data.interaction.id,
|
|
||||||
type: data.interaction.type,
|
|
||||||
name: data.interaction.name,
|
|
||||||
user: new User(data.interaction.user, client),
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.interaction.member) {
|
|
||||||
data.interaction.member.user = data.interaction.user
|
|
||||||
|
|
||||||
if (this.guild) {
|
|
||||||
this.interaction.member = new Member(
|
|
||||||
// @ts-expect-error some eris magic at play here
|
|
||||||
data.interaction.member,
|
|
||||||
this.guild,
|
|
||||||
client,
|
|
||||||
)
|
|
||||||
this.guild.members.set(this.interaction.member.id, this.interaction.member)
|
|
||||||
} else {
|
|
||||||
// @ts-expect-error some eris magic at play here
|
|
||||||
interactionMember = data.interaction.member
|
|
||||||
}
|
|
||||||
} else if (this.guild?.members.has(data.interaction.user.id)) {
|
|
||||||
this.interaction.member = this.guild.members.get(data.interaction.user.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.guild) {
|
|
||||||
if (data.member) {
|
|
||||||
data.member.user = data.author
|
|
||||||
this.member = new Member(data.member as DiscordMemberWithUser, this.guild, client)
|
|
||||||
this.guild.members.set(this.member.id, this.member)
|
|
||||||
} else if (this.guild.members.has(this.author.id)) {
|
|
||||||
this.member = this.guild.members.get(this.author.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.update(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use `.client` instead.
|
|
||||||
*/
|
|
||||||
get _client(): Client {
|
|
||||||
return this.client
|
|
||||||
}
|
|
||||||
|
|
||||||
get guild(): Guild | undefined {
|
|
||||||
return this.guildID ? this.client.guilds.get(this.guildID) : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
update(data: DiscordMessage) {
|
|
||||||
if (data.pinned !== undefined) this.pinned = !!data.pinned
|
|
||||||
|
|
||||||
if (data.tts !== undefined) this.tts = data.tts
|
|
||||||
if (data.attachments !== undefined) this.attachments = data.attachments
|
|
||||||
if (data.embeds !== undefined) this.embeds = data.embeds
|
|
||||||
if (data.flags !== undefined) this.flags = data.flags
|
|
||||||
if (data.activity !== undefined) this.activity = data.activity
|
|
||||||
if (data.components !== undefined) this.components = data.components
|
|
||||||
if (data.application !== undefined) this.application = data.application
|
|
||||||
|
|
||||||
if (data.edited_timestamp) this.editedTimestamp = Date.parse(data.edited_timestamp)
|
|
||||||
if (data.application_id !== undefined) this.applicationID = data.application_id
|
|
||||||
if (data.sticker_items !== undefined) this.stickerItems = data.sticker_items
|
|
||||||
|
|
||||||
if (data.content !== undefined) {
|
|
||||||
this.content = data.content || ''
|
|
||||||
this.mentionEveryone = !!data.mention_everyone
|
|
||||||
this.mentions = []
|
|
||||||
|
|
||||||
for (const mention of data.mentions ?? []) {
|
|
||||||
const user = new User(mention, this.client)
|
|
||||||
this.client.users.set(user.id, user)
|
|
||||||
|
|
||||||
if (mention.member && this.guild) {
|
|
||||||
mention.member.user = mention
|
|
||||||
this.guild.members.set(mention.id, new Member(mention.member as DiscordMemberWithUser, this.guild, this.client))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.mention_roles) this.roleMentions = data.mention_roles
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.reactions) {
|
|
||||||
for (const reaction of data.reactions ?? []) {
|
|
||||||
this.reactions[reaction.emoji.id ? `${reaction.emoji.name}:${reaction.emoji.id}` : reaction.emoji.name!] = {
|
|
||||||
count: reaction.count,
|
|
||||||
me: reaction.me,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get channelMentions(): string[] {
|
|
||||||
return (this.content.match(/<#[0-9]+>/g) ?? []).map((mention) => mention.substring(2, mention.length - 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
get cleanContent() {
|
|
||||||
let cleanContent = this.content?.replace(/<a?(:\w+:)[0-9]+>/g, '$1') || ''
|
|
||||||
|
|
||||||
let authorName = this.author.username
|
|
||||||
if (this.guild) {
|
|
||||||
const member = this.guild.members.get(this.author.id)
|
|
||||||
if (member?.nick) {
|
|
||||||
authorName = member.nick
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cleanContent = cleanContent.replace(new RegExp(`<@!?${this.author.id}>`, 'g'), '@\u200b' + authorName)
|
|
||||||
|
|
||||||
if (this.mentions) {
|
|
||||||
this.mentions.forEach((mention) => {
|
|
||||||
if (this.guild) {
|
|
||||||
const member = this.guild.members.get(mention.id)
|
|
||||||
if (member?.nick) {
|
|
||||||
cleanContent = cleanContent.replace(new RegExp(`<@!?${mention.id}>`, 'g'), '@\u200b' + member.nick)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cleanContent = cleanContent.replace(new RegExp(`<@!?${mention.id}>`, 'g'), '@\u200b' + mention.username)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.guild && this.roleMentions) {
|
|
||||||
for (const roleID of this.roleMentions) {
|
|
||||||
const role = this.guild.roles.get(roleID)
|
|
||||||
const roleName = role ? role.name : 'deleted-role'
|
|
||||||
cleanContent = cleanContent.replace(new RegExp(`<@&${roleID}>`, 'g'), '@\u200b' + roleName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.channelMentions.forEach((id) => {
|
|
||||||
const channel = this.client.getChannel(id) as TextChannel
|
|
||||||
if (channel?.name && channel.mention) {
|
|
||||||
cleanContent = cleanContent.replace(channel.mention, '#' + channel.name)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return cleanContent.replace(/@everyone/g, '@\u200beveryone').replace(/@here/g, '@\u200bhere')
|
|
||||||
}
|
|
||||||
|
|
||||||
get jumpLink() {
|
|
||||||
return `${this.client.CLIENT_URL}${MESSAGE_LINK(this.guildID ?? '@me', this.channel.id, this.id)}`
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Add a reaction to a message */
|
|
||||||
async addReaction(reaction: string): Promise<void> {
|
|
||||||
if (this.flags & MessageFlags.EPHEMERAL) {
|
|
||||||
throw new Error('Ephemeral messages cannot have reactions')
|
|
||||||
}
|
|
||||||
return await this.client.addMessageReaction.call(this.client, this.channel.id, this.id, reaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a thread with this message */
|
|
||||||
async createThreadWithMessage(options: {
|
|
||||||
name: string
|
|
||||||
autoArchiveDuration: 60 | 1440 | 4320 | 10080
|
|
||||||
}): Promise<NewsThreadChannel | PublicThreadChannel> {
|
|
||||||
return await this.client.createThreadWithMessage.call(this.client, this.channel.id, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Crosspost (publish) a message to subscribed channels (NewsChannel only) */
|
|
||||||
async crosspost(): Promise<Message> {
|
|
||||||
if (this.flags & MessageFlags.EPHEMERAL) {
|
|
||||||
throw new Error('Ephemeral messages cannot be crossposted')
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.crosspostMessage.call(this.client, this.channel.id, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete the message */
|
|
||||||
async delete(reason?: string): Promise<void> {
|
|
||||||
if (this.flags & MessageFlags.EPHEMERAL) {
|
|
||||||
throw new Error('Ephemeral messages cannot be deleted')
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.deleteMessage.call(this.client, this.channel.id, this.id, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete the message as a webhook */
|
|
||||||
async deleteWebhook(token: string): Promise<void> {
|
|
||||||
if (!this.webhookID) throw new Error('Message is not a webhook')
|
|
||||||
if (this.flags & MessageFlags.EPHEMERAL) throw new Error('Ephemeral messages cannot be deleted')
|
|
||||||
|
|
||||||
return await this.client.deleteWebhookMessage.call(this.client, this.webhookID, token, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit the message */
|
|
||||||
async edit(content: MessageContentEdit): Promise<Message> {
|
|
||||||
if (this.flags & MessageFlags.EPHEMERAL) {
|
|
||||||
throw new Error('Ephemeral messages cannot be edited via this method')
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.editMessage.call(this.client, this.channel.id, this.id, content)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit the message as a webhook */
|
|
||||||
async editWebhook(token: string, options: MessageWebhookContent): Promise<Message> {
|
|
||||||
if (!this.webhookID) {
|
|
||||||
throw new Error('Message is not a webhook')
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.editWebhookMessage.call(this.client, this.webhookID, token, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a list of users who reacted with a specific reaction */
|
|
||||||
async getReaction(reaction: string, options?: GetMessageReactionOptions): Promise<User[]> {
|
|
||||||
if (this.flags & MessageFlags.EPHEMERAL) {
|
|
||||||
throw new Error('Ephemeral messages cannot have reactions')
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.getMessageReaction.call(this.client, this.channel.id, this.id, reaction, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Pin the message */
|
|
||||||
async pin(): Promise<void> {
|
|
||||||
if (this.flags & MessageFlags.EPHEMERAL) {
|
|
||||||
throw new Error('Ephemeral messages cannot be pinned')
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.pinMessage.call(this.client, this.channel.id, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Remove a reaction from a message */
|
|
||||||
async removeReaction(reaction: string): Promise<void> {
|
|
||||||
if (this.flags & MessageFlags.EPHEMERAL) {
|
|
||||||
throw new Error('Ephemeral messages cannot have reactions')
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.removeMessageReaction.call(this.client, this.channel.id, this.id, reaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Remove all reactions from a message for a single emoji */
|
|
||||||
async removeReactionEmoji(reaction: string): Promise<void> {
|
|
||||||
if (this.flags & MessageFlags.EPHEMERAL) {
|
|
||||||
throw new Error('Ephemeral messages cannot have reactions')
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.removeMessageReactionEmoji.call(this.client, this.channel.id, this.id, reaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Remove all reactions from a message */
|
|
||||||
async removeReactions(): Promise<void> {
|
|
||||||
if (this.flags & MessageFlags.EPHEMERAL) {
|
|
||||||
throw new Error('Ephemeral messages cannot have reactions')
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.removeMessageReactions.call(this.client, this.channel.id, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Unpin the message */
|
|
||||||
async unpin(): Promise<void> {
|
|
||||||
if (this.flags & MessageFlags.EPHEMERAL) {
|
|
||||||
throw new Error('Ephemeral messages cannot be pinned')
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.unpinMessage.call(this.client, this.channel.id, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON([
|
|
||||||
'activity',
|
|
||||||
'application',
|
|
||||||
'attachments',
|
|
||||||
'author',
|
|
||||||
'content',
|
|
||||||
'editedTimestamp',
|
|
||||||
'embeds',
|
|
||||||
'flags',
|
|
||||||
'guildID',
|
|
||||||
'hit',
|
|
||||||
'member',
|
|
||||||
'mentionEveryone',
|
|
||||||
'mentions',
|
|
||||||
'messageReference',
|
|
||||||
'pinned',
|
|
||||||
'reactions',
|
|
||||||
'referencedMesssage',
|
|
||||||
'roleMentions',
|
|
||||||
'stickers',
|
|
||||||
'stickerItems',
|
|
||||||
'timestamp',
|
|
||||||
'tts',
|
|
||||||
'type',
|
|
||||||
'webhookID',
|
|
||||||
...props,
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Message
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
import { BitwisePermissionFlags } from '@discordeno/types'
|
|
||||||
import { Base } from '../Base.js'
|
|
||||||
import type { BigString } from '../Client.js'
|
|
||||||
import type { PermissionClientStrings } from '../Constants.js'
|
|
||||||
import { Permissions } from '../Constants.js'
|
|
||||||
|
|
||||||
export class Permission {
|
|
||||||
allow: bigint
|
|
||||||
deny: bigint
|
|
||||||
_json?: Record<string, boolean>
|
|
||||||
|
|
||||||
constructor(allow: BigString | number = 0, deny: BigString | number = 0) {
|
|
||||||
this.allow = BigInt(allow)
|
|
||||||
this.deny = BigInt(deny)
|
|
||||||
}
|
|
||||||
|
|
||||||
get isAdmin(): boolean {
|
|
||||||
return !!(this.allow & BigInt(BitwisePermissionFlags.ADMINISTRATOR))
|
|
||||||
}
|
|
||||||
|
|
||||||
get json() {
|
|
||||||
if (!this._json) {
|
|
||||||
this._json = {}
|
|
||||||
for (const key of Object.keys(BitwisePermissionFlags)) {
|
|
||||||
if (typeof key === 'number') continue
|
|
||||||
|
|
||||||
const perm = key as keyof typeof BitwisePermissionFlags
|
|
||||||
|
|
||||||
if (this.allow & BigInt(BitwisePermissionFlags[perm])) {
|
|
||||||
this._json[perm] = true
|
|
||||||
} else if (this.deny & BigInt(BitwisePermissionFlags[perm])) {
|
|
||||||
this._json[perm] = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this._json
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Check if this permission allows a specific permission */
|
|
||||||
has(permission: bigint | PermissionClientStrings): boolean {
|
|
||||||
if (this.isAdmin) return true
|
|
||||||
|
|
||||||
if (typeof permission === 'bigint') {
|
|
||||||
return (this.allow & permission) === permission
|
|
||||||
}
|
|
||||||
return !!(this.allow & Permissions[permission])
|
|
||||||
}
|
|
||||||
|
|
||||||
toString() {
|
|
||||||
return `[${this.constructor.name} +${this.allow} -${this.deny}]`
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return Base.prototype.toJSON.call(['allow', 'deny', ...props])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Permission
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import type { DiscordOverwrite, OverwriteTypes } from '@discordeno/types'
|
|
||||||
import { Base } from '../Base.js'
|
|
||||||
import Permission from './Permission.js'
|
|
||||||
|
|
||||||
export class PermissionOverwrite extends Permission {
|
|
||||||
id: string
|
|
||||||
type: OverwriteTypes
|
|
||||||
|
|
||||||
constructor(data: DiscordOverwrite) {
|
|
||||||
super(data.allow, data.deny)
|
|
||||||
|
|
||||||
this.id = data.id
|
|
||||||
this.type = data.type
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return Base.prototype.toJSON.call(['id', 'type', ...props])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PermissionOverwrite
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import type { BigString } from '@discordeno/types'
|
|
||||||
import type Collection from '../../Collection.js'
|
|
||||||
import type { AnyGuildChannel } from '../../typings.js'
|
|
||||||
import GuildChannel from './Guild.js'
|
|
||||||
|
|
||||||
export class CategoryChannel extends GuildChannel {
|
|
||||||
get channels(): Collection<BigString, Exclude<AnyGuildChannel, CategoryChannel>> {
|
|
||||||
return this.guild?.channels.filter((c) => c.parentID === this.id) as unknown as Collection<BigString, Exclude<AnyGuildChannel, CategoryChannel>>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default CategoryChannel
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
import type { ChannelTypes, DiscordChannel } from '@discordeno/types'
|
|
||||||
import Base from '../../Base.js'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
|
|
||||||
export class Channel extends Base {
|
|
||||||
type: ChannelTypes
|
|
||||||
client: Client
|
|
||||||
|
|
||||||
constructor(data: DiscordChannel | Pick<DiscordChannel, 'id' | 'permissions' | 'name' | 'type'>, client: Client) {
|
|
||||||
super(data.id)
|
|
||||||
this.type = data.type
|
|
||||||
this.client = client
|
|
||||||
}
|
|
||||||
|
|
||||||
get mention(): string {
|
|
||||||
return `<#${this.id}>`
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Removed this circular dependency hack for better alternative.
|
|
||||||
*/
|
|
||||||
static from(_data: DiscordChannel, client: Client): void {
|
|
||||||
console.error('Usage of channel.from is deprecated, please use generateChannelFrom(data, client)')
|
|
||||||
client.emit('warn', new Error(`Usage of "Channel.from" is deprecated. Use "generateChanneFrom()"`))
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON(['type', ...props])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Channel
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
/* eslint-disable no-useless-call */
|
|
||||||
import type { BigString, DiscordChannel, OverwriteTypes } from '@discordeno/types'
|
|
||||||
import { BitwisePermissionFlags, ChannelTypes } from '@discordeno/types'
|
|
||||||
import { Collection } from '@discordeno/utils'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
import type { EditChannelOptions, EditChannelPositionOptions } from '../../typings.js'
|
|
||||||
import type Guild from '../guilds/Guild.js'
|
|
||||||
import type Member from '../guilds/Member.js'
|
|
||||||
import Permission from '../Permission.js'
|
|
||||||
import PermissionOverwrite from '../PermissionOverwrite.js'
|
|
||||||
import Channel from './Channel.js'
|
|
||||||
|
|
||||||
export class GuildChannel extends Channel {
|
|
||||||
position: number
|
|
||||||
name: string
|
|
||||||
parentID?: string | null
|
|
||||||
guild: Guild
|
|
||||||
nsfw: boolean
|
|
||||||
permissionOverwrites = new Collection<BigString, PermissionOverwrite>()
|
|
||||||
/** The RTC region ID of the channel (automatic if `null`) (guild voice channels only) */
|
|
||||||
rtcRegion: string | null = null
|
|
||||||
|
|
||||||
constructor(data: DiscordChannel, client: Client) {
|
|
||||||
super(data, client)
|
|
||||||
|
|
||||||
this.position = data.position ?? 0
|
|
||||||
this.guild = client.guilds.get(data.guild_id!)!
|
|
||||||
this.name = data.name ?? ''
|
|
||||||
this.parentID = data.parent_id
|
|
||||||
this.nsfw = !!data.nsfw
|
|
||||||
}
|
|
||||||
|
|
||||||
update(data: DiscordChannel): void {
|
|
||||||
if (data.type !== undefined) {
|
|
||||||
this.type = data.type
|
|
||||||
}
|
|
||||||
if (data.name !== undefined) {
|
|
||||||
this.name = data.name
|
|
||||||
}
|
|
||||||
if (data.position !== undefined) {
|
|
||||||
this.position = data.position
|
|
||||||
}
|
|
||||||
if (data.parent_id !== undefined) {
|
|
||||||
this.parentID = data.parent_id
|
|
||||||
}
|
|
||||||
this.nsfw = !!data.nsfw
|
|
||||||
if (data.permission_overwrites) {
|
|
||||||
data.permission_overwrites.forEach((overwrite) => {
|
|
||||||
const perms = new PermissionOverwrite(overwrite)
|
|
||||||
this.permissionOverwrites.set(perms.id, perms)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete the channel */
|
|
||||||
async delete(reason?: string): Promise<void> {
|
|
||||||
return await this.client.deleteChannel.call(this.client, this.id, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete a channel permission overwrite */
|
|
||||||
async deletePermission(overwriteID: BigString, reason?: string): Promise<void> {
|
|
||||||
return await this.client.deleteChannelPermission.call(this.client, this.id, overwriteID, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit the channel's properties */
|
|
||||||
async edit(options: EditChannelOptions, reason?: string) {
|
|
||||||
return await this.client.editChannel.call(this.client, this.id, options, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a channel permission overwrite */
|
|
||||||
async editPermission(overwriteID: BigString, allow: bigint | number, deny: bigint | number, type: OverwriteTypes, reason?: string): Promise<void> {
|
|
||||||
return await this.client.editChannelPermission.call(this.client, this.id, overwriteID, allow, deny, type, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit the channel's position. Note that channel position numbers are lowest on top and highest at the bottom. */
|
|
||||||
async editPosition(position: number, options?: EditChannelPositionOptions): Promise<void> {
|
|
||||||
return await this.client.editChannelPosition.call(this.client, this.id, position, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the channel-specific permissions of a member */
|
|
||||||
permissionsOf(memberID: BigString | Member): Permission {
|
|
||||||
const member = ['string', 'bigint'].includes(typeof memberID) ? this.guild.members.get(memberID as BigString)! : (memberID as Member)
|
|
||||||
let permission = this.guild.permissionsOf(member).allow
|
|
||||||
if (permission & BigInt(BitwisePermissionFlags.ADMINISTRATOR)) {
|
|
||||||
return new Permission(BitwisePermissionFlags.ADMINISTRATOR)
|
|
||||||
}
|
|
||||||
const channel =
|
|
||||||
[ChannelTypes.PublicThread, ChannelTypes.PrivateThread, ChannelTypes.AnnouncementThread].includes(this.type) && this.parentID
|
|
||||||
? this.guild.channels.get(this.parentID)
|
|
||||||
: this
|
|
||||||
let overwrite = channel?.permissionOverwrites.get(this.guild.id)
|
|
||||||
if (overwrite) {
|
|
||||||
permission = (permission & ~overwrite.deny) | overwrite.allow
|
|
||||||
}
|
|
||||||
let deny = 0n
|
|
||||||
let allow = 0n
|
|
||||||
for (const roleID of member.roles) {
|
|
||||||
if ((overwrite = channel?.permissionOverwrites.get(roleID))) {
|
|
||||||
deny |= overwrite.deny
|
|
||||||
allow |= overwrite.allow
|
|
||||||
}
|
|
||||||
}
|
|
||||||
permission = (permission & ~deny) | allow
|
|
||||||
overwrite = channel?.permissionOverwrites.get(member.id)
|
|
||||||
if (overwrite) {
|
|
||||||
permission = (permission & ~overwrite.deny) | overwrite.allow
|
|
||||||
}
|
|
||||||
return new Permission(permission)
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON(['name', 'nsfw', 'parentID', 'permissionOverwrites', 'position', ...props])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default GuildChannel
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/* eslint-disable no-useless-call */
|
|
||||||
/* eslint-disable @typescript-eslint/return-await */
|
|
||||||
import type { BigString, DiscordChannel } from '@discordeno/types'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
import type { ChannelFollow } from '../../typings.js'
|
|
||||||
import type Message from '../Message.js'
|
|
||||||
import TextChannel from './Text.js'
|
|
||||||
|
|
||||||
export class NewsChannel extends TextChannel {
|
|
||||||
constructor(data: DiscordChannel, client: Client, messageLimit?: number) {
|
|
||||||
super(data, client, messageLimit)
|
|
||||||
|
|
||||||
this.rateLimitPerUser = 0
|
|
||||||
this.update(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Crosspost (publish) a message to subscribed channels */
|
|
||||||
async crosspostMessage(messageID: BigString): Promise<Message> {
|
|
||||||
return await this.client.crosspostMessage.call(this.client, this.id, messageID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Follow this channel in another channel. This creates a webhook in the target channel */
|
|
||||||
async follow(webhookChannelID: BigString): Promise<ChannelFollow> {
|
|
||||||
return await this.client.followChannel.call(this.client, this.id, webhookChannelID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default NewsChannel
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
/* eslint-disable no-useless-call */
|
|
||||||
import { ChannelTypes, type BigString, type DiscordChannel, type GetMessagesOptions } from '@discordeno/types'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
import Collection from '../../Collection.js'
|
|
||||||
import type { FileContent, GetMessageReactionOptions, MessageContent, MessageContentEdit } from '../../typings.js'
|
|
||||||
import type Message from '../Message.js'
|
|
||||||
import User from '../users/User.js'
|
|
||||||
import Channel from './Channel.js'
|
|
||||||
|
|
||||||
export class PrivateChannel extends Channel {
|
|
||||||
/** The ID of the last message in this channel */
|
|
||||||
lastMessageID = ""
|
|
||||||
// TODO: THIS A THING IN DMS????
|
|
||||||
/** The rate limit per user. */
|
|
||||||
rateLimitPerUser?: number
|
|
||||||
/** Collection of Messages in this channel */
|
|
||||||
messages: Collection<string, Message>
|
|
||||||
/** The recipient in this private channel */
|
|
||||||
recipient?: User
|
|
||||||
|
|
||||||
constructor(data: DiscordChannel, client: Client) {
|
|
||||||
super(data, client)
|
|
||||||
|
|
||||||
this.lastMessageID = data.last_message_id ?? ""
|
|
||||||
this.rateLimitPerUser = data.rate_limit_per_user
|
|
||||||
if (this.type === ChannelTypes.DM || this.type === undefined) {
|
|
||||||
if (data.recipients?.[0]) this.recipient = new User(data.recipients[0], client)
|
|
||||||
}
|
|
||||||
this.messages = new Collection()
|
|
||||||
this.messages.limit = client.options.messageLimit
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Add a reaction to a message */
|
|
||||||
async addMessageReaction(messageID: BigString, reaction: string): Promise<void> {
|
|
||||||
return await this.client.addMessageReaction.call(this.client, this.id, messageID, reaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a message in a text channel */
|
|
||||||
async createMessage(content: MessageContent, file?: FileContent | FileContent[]): Promise<Message> {
|
|
||||||
return await this.client.createMessage.call(this.client, this.id, content, file)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: REASONS ARE A THING FOR AUDIT LOGS IN DMS???
|
|
||||||
/** Delete a message */
|
|
||||||
async deleteMessage(messageID: BigString, reason?: string): Promise<void> {
|
|
||||||
return await this.client.deleteMessage.call(this.client, this.id, messageID, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit a message */
|
|
||||||
async editMessage(messageID: BigString, content: MessageContentEdit): Promise<Message> {
|
|
||||||
return await this.client.editMessage.call(this.client, this.id, messageID, content)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a previous message in a text channel */
|
|
||||||
async getMessage(messageID: BigString): Promise<Message> {
|
|
||||||
return await this.client.getMessage.call(this.client, this.id, messageID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a list of users who reacted with a specific reaction */
|
|
||||||
async getMessageReaction(messageID: BigString, reaction: string, options: GetMessageReactionOptions): Promise<User[]> {
|
|
||||||
return await this.client.getMessageReaction.call(this.client, this.id, messageID, reaction, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a previous message in a text channel */
|
|
||||||
async getMessages(options: GetMessagesOptions): Promise<Message[]> {
|
|
||||||
return await this.client.getMessages.call(this.client, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get all the pins in a text channel */
|
|
||||||
async getPins(): Promise<Message[]> {
|
|
||||||
return await this.client.getPins.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Leave the channel */
|
|
||||||
async leave(): Promise<void> {
|
|
||||||
return await this.client.deleteChannel.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Pin a message */
|
|
||||||
async pinMessage(messageID: BigString): Promise<void> {
|
|
||||||
return await this.client.pinMessage.call(this.client, this.id, messageID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Remove a reaction from a message */
|
|
||||||
async removeMessageReaction(messageID: BigString, reaction: string): Promise<void> {
|
|
||||||
return await this.client.removeMessageReaction.call(this.client, this.id, messageID, reaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Send typing status in a text channel */
|
|
||||||
async sendTyping(): Promise<void> {
|
|
||||||
return await this.client.sendChannelTyping.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Unpin a message */
|
|
||||||
async unpinMessage(messageID: BigString): Promise<void> {
|
|
||||||
return await this.client.unpinMessage.call(this.client, this.id, messageID)
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON(['call', 'lastCall', 'lastMessageID', 'messages', 'recipient', ...props])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PrivateChannel
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/* eslint-disable no-useless-call */
|
|
||||||
/* eslint-disable @typescript-eslint/return-await */
|
|
||||||
import type { DiscordChannel } from '@discordeno/types'
|
|
||||||
import type { StageInstanceOptions } from '../../typings.js'
|
|
||||||
import type StageInstance from '../guilds/StageInstance.js'
|
|
||||||
import VoiceChannel from './Voice.js'
|
|
||||||
|
|
||||||
export class StageChannel extends VoiceChannel {
|
|
||||||
/** The topic of the channel */
|
|
||||||
topic?: string | null
|
|
||||||
|
|
||||||
update(data: DiscordChannel): void {
|
|
||||||
super.update(data)
|
|
||||||
|
|
||||||
if (data.topic !== undefined) {
|
|
||||||
this.topic = data.topic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a stage instance */
|
|
||||||
async createInstance(options: StageInstanceOptions): Promise<StageInstance> {
|
|
||||||
return await this.client.createStageInstance.call(this.client, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete the stage instance for this channel */
|
|
||||||
async deleteInstance(): Promise<void> {
|
|
||||||
return await this.client.deleteStageInstance.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Update the stage instance for this channel */
|
|
||||||
async editInstance(options: StageInstanceOptions): Promise<StageInstance> {
|
|
||||||
return await this.client.editStageInstance.call(this.client, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the stage instance for this channel */
|
|
||||||
async getInstance(): Promise<StageInstance> {
|
|
||||||
return await this.client.getStageInstance.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON(['topic', ...props])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default StageChannel
|
|
||||||
@@ -1,376 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
/* eslint-disable no-useless-call */
|
|
||||||
/* eslint-disable @typescript-eslint/return-await */
|
|
||||||
import type { BigString, DiscordChannel, GetMessagesOptions } from '@discordeno/types'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
import Collection from '../../Collection.js'
|
|
||||||
import type {
|
|
||||||
CreateChannelInviteOptions,
|
|
||||||
CreateThreadOptions,
|
|
||||||
CreateThreadWithoutMessageOptions,
|
|
||||||
FileContent,
|
|
||||||
GetArchivedThreadsOptions,
|
|
||||||
GetMessageReactionOptions,
|
|
||||||
ListedChannelThreads,
|
|
||||||
MessageContent,
|
|
||||||
MessageContentEdit,
|
|
||||||
PurgeChannelOptions,
|
|
||||||
} from '../../typings.js'
|
|
||||||
import type Invite from '../Invite.js'
|
|
||||||
import type Message from '../Message.js'
|
|
||||||
import GuildChannel from './Guild.js'
|
|
||||||
import type PrivateThreadChannel from './threads/PrivateThread.js'
|
|
||||||
import type PublicThreadChannel from './threads/PublicThread.js'
|
|
||||||
|
|
||||||
export class TextChannel extends GuildChannel {
|
|
||||||
/** Collection of Messages in this channel */
|
|
||||||
messages: Collection<string, Message>
|
|
||||||
/** The ratelimit of the channel, in seconds. 0 means no ratelimit is enabled */
|
|
||||||
rateLimitPerUser: number | null
|
|
||||||
/** The ID of the last message in this channel */
|
|
||||||
lastMessageID = ""
|
|
||||||
/** The timestamp of the last pinned message */
|
|
||||||
lastPinTimestamp?: number | null
|
|
||||||
/** Default duration for newly created threads, in minutes, to automatically archive the thread after recent activity, can be set to: 60, 1440, 4320, 10080 */
|
|
||||||
defaultAutoArchiveDuration?: number
|
|
||||||
/** The channel topic (0-4096 characters for GUILD_FORUM channels, 0-1024 characters for all others) */
|
|
||||||
topic?: string | null
|
|
||||||
|
|
||||||
constructor(data: DiscordChannel, client: Client, messageLimit?: number) {
|
|
||||||
super(data, client)
|
|
||||||
|
|
||||||
this.messages = new Collection()
|
|
||||||
if (messageLimit == null) this.messages.limit = client.options.messageLimit
|
|
||||||
else this.messages.limit = messageLimit
|
|
||||||
|
|
||||||
this.rateLimitPerUser = data.rate_limit_per_user == null ? null : data.rate_limit_per_user
|
|
||||||
|
|
||||||
this.lastMessageID = data.last_message_id ?? ""
|
|
||||||
this.lastPinTimestamp = data.last_pin_timestamp ? Date.parse(data.last_pin_timestamp) : null
|
|
||||||
|
|
||||||
this.update(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
update(data: DiscordChannel): void {
|
|
||||||
super.update(data)
|
|
||||||
|
|
||||||
if (data.rate_limit_per_user !== undefined) this.rateLimitPerUser = data.rate_limit_per_user
|
|
||||||
if (data.topic !== undefined) this.topic = data.topic
|
|
||||||
if (data.default_auto_archive_duration !== undefined) this.defaultAutoArchiveDuration = data.default_auto_archive_duration
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Add a reaction to a message */
|
|
||||||
async addMessageReaction(messageID: BigString, reaction: string): Promise<void> {
|
|
||||||
return this.client.addMessageReaction.call(this.client, this.id, messageID, reaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create an invite for the channel */
|
|
||||||
async createInvite(options?: CreateChannelInviteOptions, reason?: string): Promise<Invite> {
|
|
||||||
return await this.client.createChannelInvite.call(this.client, this.id, options, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a message in the channel
|
|
||||||
* @arg {String | Object} content A string or object. If an object is passed:
|
|
||||||
* @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default)
|
|
||||||
* @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here.
|
|
||||||
* @arg {Boolean | Array<String>} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow.
|
|
||||||
* @arg {Boolean | Array<String>} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow.
|
|
||||||
* @arg {Boolean} [content.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to.
|
|
||||||
* @arg {Array<Object>} [content.components] An array of component objects
|
|
||||||
* @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only)
|
|
||||||
* @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only)
|
|
||||||
* @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2)
|
|
||||||
* @arg {String} [content.components[].label] The label to be displayed in the component (type 2)
|
|
||||||
* @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1)
|
|
||||||
* @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1)
|
|
||||||
* @arg {Array<Object>} [content.components[].options] The options for this component (type 3 only)
|
|
||||||
* @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected
|
|
||||||
* @arg {String} [content.components[].options[].description] The description for this option
|
|
||||||
* @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option
|
|
||||||
* @arg {String} content.components[].options[].label The label for this option
|
|
||||||
* @arg {Number | String} content.components[].options[].value The value for this option
|
|
||||||
* @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only)
|
|
||||||
* @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required
|
|
||||||
* @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu
|
|
||||||
* @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only)
|
|
||||||
* @arg {String} [content.content] A content string
|
|
||||||
* @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure
|
|
||||||
* @arg {Array<Object>} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure
|
|
||||||
* @arg {Object} [content.messageReference] The message reference, used when replying to messages
|
|
||||||
* @arg {String} [content.messageReference.channelID] The channel ID of the referenced message
|
|
||||||
* @arg {Boolean} [content.messageReference.failIfNotExists=true] Whether to throw an error if the message reference doesn't exist. If false, and the referenced message doesn't exist, the message is created without a referenced message
|
|
||||||
* @arg {String} [content.messageReference.guildID] The guild ID of the referenced message
|
|
||||||
* @arg {String} content.messageReference.messageID The message ID of the referenced message. This cannot reference a system message
|
|
||||||
* @arg {String} [content.messageReferenceID] [DEPRECATED] The ID of the message should be replied to. Use `messageReference` instead
|
|
||||||
* @arg {Array<String>} [content.stickerIDs] An array of IDs corresponding to stickers to send
|
|
||||||
* @arg {Boolean} [content.tts] Set the message TTS flag
|
|
||||||
* @arg {Object | Array<Object>} [file] A file object (or an Array of them)
|
|
||||||
* @arg {Buffer} file.file A buffer containing file data
|
|
||||||
* @arg {String} file.name What to name the file
|
|
||||||
* @returns {Promise<Message>}
|
|
||||||
*/
|
|
||||||
async createMessage(content: MessageContent, file?: FileContent | FileContent[]) {
|
|
||||||
return this.client.createMessage.call(this.client, this.id, content, file)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a thread with an existing message
|
|
||||||
* @arg {String} messageID The ID of the message to create the thread from
|
|
||||||
* @arg {Object} options The thread options
|
|
||||||
* @arg {Number} options.autoArchiveDuration Duration in minutes to automatically archive the thread after recent activity, either 60, 1440, 4320 or 10080
|
|
||||||
* @arg {String} options.name The thread channel name
|
|
||||||
* @returns {Promise<NewsThreadChannel | PublicThreadChannel>}
|
|
||||||
*/
|
|
||||||
async createThreadWithMessage(messageID: string, options: CreateThreadOptions) {
|
|
||||||
return this.client.createThreadWithMessage.call(this.client, this.id, messageID, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a thread without an existing message
|
|
||||||
* @arg {Object} options The thread options
|
|
||||||
* @arg {Number} options.autoArchiveDuration Duration in minutes to automatically archive the thread after recent activity, either 60, 1440, 4320 or 10080
|
|
||||||
* @arg {boolean} [options.invitable] Whether non-moderators can add other non-moderators to the thread (private threads only)
|
|
||||||
* @arg {String} options.name The thread channel name
|
|
||||||
* @arg {Number} [options.type] The channel type of the thread to create. It is recommended to explicitly set this property as this will be a required property in API v10
|
|
||||||
* @returns {Promise<PrivateThreadChannel>}
|
|
||||||
*/
|
|
||||||
async createThreadWithoutMessage(options: CreateThreadWithoutMessageOptions) {
|
|
||||||
return this.client.createThreadWithoutMessage.call(this.client, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a channel webhook
|
|
||||||
* @arg {Object} options Webhook options
|
|
||||||
* @arg {String} [options.avatar] The default avatar as a base64 data URI. Note: base64 strings alone are not base64 data URI strings
|
|
||||||
* @arg {String} options.name The default name
|
|
||||||
* @arg {String} [reason] The reason to be displayed in audit logs
|
|
||||||
* @returns {Promise<Object>} Resolves with a webhook object
|
|
||||||
*/
|
|
||||||
async createWebhook(options: { name: string; avatar?: string | null }, reason: string) {
|
|
||||||
return this.client.createChannelWebhook.call(this.client, this.id, options, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a message
|
|
||||||
* @arg {String} messageID The ID of the message
|
|
||||||
* @arg {String} [reason] The reason to be displayed in audit logs
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async deleteMessage(messageID: string, reason: string) {
|
|
||||||
return this.client.deleteMessage.call(this.client, this.id, messageID, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bulk delete messages (bot accounts only)
|
|
||||||
* @arg {Array<String>} messageIDs Array of message IDs to delete
|
|
||||||
* @arg {String} [reason] The reason to be displayed in audit logs
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async deleteMessages(messageIDs: string[], reason: string) {
|
|
||||||
return this.client.deleteMessages.call(this.client, this.id, messageIDs, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Edit a message
|
|
||||||
* @arg {String} messageID The ID of the message
|
|
||||||
* @arg {String | Array | Object} content A string, array of strings, or object. If an object is passed:
|
|
||||||
* @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default)
|
|
||||||
* @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here.
|
|
||||||
* @arg {Boolean | Array<String>} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow.
|
|
||||||
* @arg {Boolean | Array<String>} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow.
|
|
||||||
* @arg {Array<Object>} [content.components] An array of component objects
|
|
||||||
* @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only)
|
|
||||||
* @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only)
|
|
||||||
* @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2)
|
|
||||||
* @arg {String} [content.components[].label] The label to be displayed in the component (type 2)
|
|
||||||
* @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1)
|
|
||||||
* @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1)
|
|
||||||
* @arg {Array<Object>} [content.components[].options] The options for this component (type 3 only)
|
|
||||||
* @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected
|
|
||||||
* @arg {String} [content.components[].options[].description] The description for this option
|
|
||||||
* @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option
|
|
||||||
* @arg {String} content.components[].options[].label The label for this option
|
|
||||||
* @arg {Number | String} content.components[].options[].value The value for this option
|
|
||||||
* @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only)
|
|
||||||
* @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required
|
|
||||||
* @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu
|
|
||||||
* @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only)
|
|
||||||
* @arg {String} [content.content] A content string
|
|
||||||
* @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure
|
|
||||||
* @arg {Array<Object>} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure
|
|
||||||
* @arg {Object | Array<Object>} [content.file] A file object (or an Array of them)
|
|
||||||
* @arg {Buffer} content.file[].file A buffer containing file data
|
|
||||||
* @arg {String} content.file[].name What to name the file
|
|
||||||
* @arg {Number} [content.flags] A number representing the flags to apply to the message. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for flags reference
|
|
||||||
* @returns {Promise<Message>}
|
|
||||||
*/
|
|
||||||
async editMessage(messageID: string, content: MessageContentEdit) {
|
|
||||||
return this.client.editMessage.call(this.client, this.id, messageID, content)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get all archived threads in this channel */
|
|
||||||
async getArchivedThreads(type: 'private', options?: GetArchivedThreadsOptions): Promise<ListedChannelThreads<PrivateThreadChannel>>
|
|
||||||
async getArchivedThreads(type: 'public', options?: GetArchivedThreadsOptions): Promise<ListedChannelThreads<PublicThreadChannel>>
|
|
||||||
async getArchivedThreads(
|
|
||||||
type: 'public' | 'private',
|
|
||||||
options?: GetArchivedThreadsOptions,
|
|
||||||
): Promise<ListedChannelThreads<PrivateThreadChannel | PublicThreadChannel>> {
|
|
||||||
return await this.client.getArchivedThreads.call(this.client, this.id, type as 'public', options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all invites in the channel
|
|
||||||
* @returns {Promise<Array<Invite>>}
|
|
||||||
*/
|
|
||||||
async getInvites() {
|
|
||||||
return this.client.getChannelInvites.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get joined private archived threads in this channel
|
|
||||||
* @arg {Object} [options] Additional options when requesting archived threads
|
|
||||||
* @arg {Date} [options.before] List of threads to return before the timestamp
|
|
||||||
* @arg {Number} [options.limit] Maximum number of threads to return
|
|
||||||
* @returns {Promise<Object>} An object containing an array of `threads`, an array of `members` and whether the response `hasMore` threads that could be returned in a subsequent call
|
|
||||||
*/
|
|
||||||
async getJoinedPrivateArchivedThreads(options: GetArchivedThreadsOptions) {
|
|
||||||
return this.client.getJoinedPrivateArchivedThreads.call(this.client, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a previous message in the channel
|
|
||||||
* @arg {String} messageID The ID of the message
|
|
||||||
* @returns {Promise<Message>}
|
|
||||||
*/
|
|
||||||
async getMessage(messageID: string) {
|
|
||||||
return this.client.getMessage.call(this.client, this.id, messageID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of users who reacted with a specific reaction
|
|
||||||
* @arg {String} messageID The ID of the message
|
|
||||||
* @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji)
|
|
||||||
* @arg {Object} [options] Options for the request. If this is a number, it is treated as `options.limit` ([DEPRECATED] behavior)
|
|
||||||
* @arg {Number} [options.limit=100] The maximum number of users to get
|
|
||||||
* @arg {String} [options.after] Get users after this user ID
|
|
||||||
* @returns {Promise<Array<User>>}
|
|
||||||
*/
|
|
||||||
async getMessageReaction(messageID: string, reaction: string, options: GetMessageReactionOptions) {
|
|
||||||
return this.client.getMessageReaction.call(this.client, this.id, messageID, reaction, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get previous messages in the channel
|
|
||||||
* @arg {Object} [options] Options for the request. If this is a number ([DEPRECATED] behavior), it is treated as `options.limit`
|
|
||||||
* @arg {String} [options.after] Get messages after this message ID
|
|
||||||
* @arg {String} [options.around] Get messages around this message ID (does not work with limit > 100)
|
|
||||||
* @arg {String} [options.before] Get messages before this message ID
|
|
||||||
* @arg {Number} [options.limit=50] The max number of messages to get
|
|
||||||
* @returns {Promise<Array<Message>>}
|
|
||||||
*/
|
|
||||||
async getMessages(options: GetMessagesOptions) {
|
|
||||||
return this.client.getMessages.call(this.client, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all the pins in the channel
|
|
||||||
* @returns {Promise<Array<Message>>}
|
|
||||||
*/
|
|
||||||
async getPins() {
|
|
||||||
return this.client.getPins.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all the webhooks in the channel
|
|
||||||
* @returns {Promise<Array<Object>>} Resolves with an array of webhook objects
|
|
||||||
*/
|
|
||||||
async getWebhooks() {
|
|
||||||
return this.client.getChannelWebhooks.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pin a message
|
|
||||||
* @arg {String} messageID The ID of the message
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async pinMessage(messageID: string) {
|
|
||||||
return this.client.pinMessage.call(this.client, this.id, messageID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Purge previous messages in the channel with an optional filter (bot accounts only)
|
|
||||||
* @arg {Object} options Options for the request. If this is a number ([DEPRECATED] behavior), it is treated as `options.limit`
|
|
||||||
* @arg {String} [options.after] Get messages after this message ID
|
|
||||||
* @arg {String} [options.before] Get messages before this message ID
|
|
||||||
* @arg {Function} [options.filter] Optional filter function that returns a boolean when passed a Message object
|
|
||||||
* @arg {Number} options.limit The max number of messages to search through, -1 for no limit
|
|
||||||
* @arg {String} [options.reason] The reason to be displayed in audit logs
|
|
||||||
* @returns {Promise<Number>} Resolves with the number of messages deleted
|
|
||||||
*/
|
|
||||||
async purge(limit: PurgeChannelOptions) {
|
|
||||||
return this.client.purgeChannel.call(this.client, this.id, limit)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a reaction from a message
|
|
||||||
* @arg {String} messageID The ID of the message
|
|
||||||
* @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji)
|
|
||||||
* @arg {String} [userID="@me"] The ID of the user to remove the reaction for
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async removeMessageReaction(messageID: string, reaction: string, userID: string) {
|
|
||||||
return this.client.removeMessageReaction.call(this.client, this.id, messageID, reaction, userID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all reactions from a message for a single emoji
|
|
||||||
* @arg {String} messageID The ID of the message
|
|
||||||
* @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji)
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async removeMessageReactionEmoji(messageID: string, reaction: string) {
|
|
||||||
return this.client.removeMessageReactionEmoji.call(this.client, this.id, messageID, reaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all reactions from a message
|
|
||||||
* @arg {String} messageID The ID of the message
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async removeMessageReactions(messageID: string) {
|
|
||||||
return this.client.removeMessageReactions.call(this.client, this.id, messageID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send typing status in the channel
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async sendTyping() {
|
|
||||||
return this.client.sendChannelTyping.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unpin a message
|
|
||||||
* @arg {String} messageID The ID of the message
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async unpinMessage(messageID: string) {
|
|
||||||
return this.client.unpinMessage.call(this.client, this.id, messageID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Un-send a message. You're welcome Programmix
|
|
||||||
* @arg {String} messageID The ID of the message
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async unsendMessage(messageID: string) {
|
|
||||||
return this.client.deleteMessage.call(this.client, this.id, messageID)
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON(['lastMessageID', 'lastPinTimestamp', 'messages', 'rateLimitPerUser', 'topic', ...props])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TextChannel
|
|
||||||
@@ -1,271 +0,0 @@
|
|||||||
/* eslint-disable no-useless-call */
|
|
||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
import type { DiscordChannel, GetMessagesOptions } from '@discordeno/types'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
import Collection from '../../Collection.js'
|
|
||||||
import type {
|
|
||||||
CreateInviteOptions,
|
|
||||||
FileContent,
|
|
||||||
GetMessageReactionOptions,
|
|
||||||
MessageContent,
|
|
||||||
MessageContentEdit,
|
|
||||||
PurgeChannelOptions,
|
|
||||||
} from '../../typings.js'
|
|
||||||
import type Message from '../Message.js'
|
|
||||||
import VoiceChannel from './Voice.js'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a Text-in-Voice channel. See VoiceChannel for more properties and methods.
|
|
||||||
* @extends VoiceChannel
|
|
||||||
* @prop {String} lastMessageID The ID of the last message in this channel
|
|
||||||
* @prop {Collection<Message>} messages Collection of Messages in this channel
|
|
||||||
* @prop {Number} rateLimitPerUser The ratelimit of the channel, in seconds. 0 means no ratelimit is enabled
|
|
||||||
*/
|
|
||||||
export class TextVoiceChannel extends VoiceChannel {
|
|
||||||
lastMessageID = ""
|
|
||||||
messages: Collection<string, Message>
|
|
||||||
rateLimitPerUser: number | null
|
|
||||||
|
|
||||||
constructor(data: DiscordChannel, client: Client, messageLimit?: number) {
|
|
||||||
super(data, client)
|
|
||||||
|
|
||||||
this.messages = new Collection()
|
|
||||||
if (messageLimit == null) this.messages.limit = client.options.messageLimit
|
|
||||||
else this.messages.limit = messageLimit
|
|
||||||
|
|
||||||
this.lastMessageID = data.last_message_id ?? ""
|
|
||||||
this.rateLimitPerUser = data.rate_limit_per_user == null ? null : data.rate_limit_per_user
|
|
||||||
}
|
|
||||||
|
|
||||||
update(data: DiscordChannel) {
|
|
||||||
super.update(data)
|
|
||||||
// "not yet, possibly TBD"
|
|
||||||
if (data.rate_limit_per_user !== undefined) {
|
|
||||||
this.rateLimitPerUser = data.rate_limit_per_user
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a reaction to a message
|
|
||||||
* @arg {String} messageID The ID of the message
|
|
||||||
* @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji)
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async addMessageReaction(messageID: string, reaction: string) {
|
|
||||||
return await this.client.addMessageReaction.call(this.client, this.id, messageID, reaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an invite for the channel
|
|
||||||
* @arg {Object} [options] Invite generation options
|
|
||||||
* @arg {Number} [options.maxAge] How long the invite should last in seconds
|
|
||||||
* @arg {Number} [options.maxUses] How many uses the invite should last for
|
|
||||||
* @arg {Boolean} [options.temporary] Whether the invite grants temporary membership or not
|
|
||||||
* @arg {Boolean} [options.unique] Whether the invite is unique or not
|
|
||||||
* @arg {String} [reason] The reason to be displayed in audit logs
|
|
||||||
* @returns {Promise<Invite>}
|
|
||||||
*/
|
|
||||||
async createInvite(options: CreateInviteOptions, reason: string) {
|
|
||||||
return await this.client.createChannelInvite.call(this.client, this.id, options, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a message in the channel
|
|
||||||
* Note: If you want to DM someone, the user ID is **not** the DM channel ID. use Client.getDMChannel() to get the DM channel ID for a user
|
|
||||||
* @arg {String | Object} content A string or object. If an object is passed:
|
|
||||||
* @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default)
|
|
||||||
* @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here.
|
|
||||||
* @arg {Boolean | Array<String>} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow.
|
|
||||||
* @arg {Boolean | Array<String>} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow.
|
|
||||||
* @arg {Boolean} [options.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to
|
|
||||||
* @arg {Array<Object>} [content.components] An array of component objects
|
|
||||||
* @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only)
|
|
||||||
* @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only)
|
|
||||||
* @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2)
|
|
||||||
* @arg {String} [content.components[].label] The label to be displayed in the component (type 2)
|
|
||||||
* @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1)
|
|
||||||
* @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1)
|
|
||||||
* @arg {Array<Object>} [content.components[].options] The options for this component (type 3 only)
|
|
||||||
* @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected
|
|
||||||
* @arg {String} [content.components[].options[].description] The description for this option
|
|
||||||
* @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option
|
|
||||||
* @arg {String} content.components[].options[].label The label for this option
|
|
||||||
* @arg {Number | String} content.components[].options[].value The value for this option
|
|
||||||
* @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only)
|
|
||||||
* @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required
|
|
||||||
* @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu
|
|
||||||
* @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only)
|
|
||||||
* @arg {String} content.content A content string
|
|
||||||
* @arg {Array<Object>} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure
|
|
||||||
* @arg {Object} [content.messageReference] The message reference, used when replying to messages
|
|
||||||
* @arg {String} [content.messageReference.channelID] The channel ID of the referenced message
|
|
||||||
* @arg {Boolean} [content.messageReference.failIfNotExists=true] Whether to throw an error if the message reference doesn't exist. If false, and the referenced message doesn't exist, the message is created without a referenced message
|
|
||||||
* @arg {String} [content.messageReference.guildID] The guild ID of the referenced message
|
|
||||||
* @arg {String} content.messageReference.messageID The message ID of the referenced message. This cannot reference a system message
|
|
||||||
* @arg {Array<String>} [content.stickerIDs] An array of IDs corresponding to the stickers to send
|
|
||||||
* @arg {Boolean} [content.tts] Set the message TTS flag
|
|
||||||
* @arg {Object} [file] A file object
|
|
||||||
* @arg {Buffer} file.file A buffer containing file data
|
|
||||||
* @arg {String} file.name What to name the file
|
|
||||||
* @returns {Promise<Message>}
|
|
||||||
*/
|
|
||||||
async createMessage(content: MessageContent, file?: FileContent | FileContent[]) {
|
|
||||||
return await this.client.createMessage.call(this.client, this.id, content, file)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a message
|
|
||||||
* @arg {String} messageID The ID of the message
|
|
||||||
* @arg {String} [reason] The reason to be displayed in audit logs
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async deleteMessage(messageID: string, reason: string) {
|
|
||||||
return await this.client.deleteMessage.call(this.client, this.id, messageID, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bulk delete messages (bot accounts only)
|
|
||||||
* @arg {Array<String>} messageIDs Array of message IDs to delete
|
|
||||||
* @arg {String} [reason] The reason to be displayed in audit logs
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async deleteMessages(messageIDs: string[], reason: string) {
|
|
||||||
return await this.client.deleteMessages.call(this.client, this.id, messageIDs, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Edit a message
|
|
||||||
* @arg {String} messageID The ID of the message
|
|
||||||
* @arg {String | Array | Object} content A string, array of strings, or object. If an object is passed:
|
|
||||||
* @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default)
|
|
||||||
* @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here.
|
|
||||||
* @arg {Boolean | Array<String>} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow.
|
|
||||||
* @arg {Boolean | Array<String>} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow.
|
|
||||||
* @arg {Array<Object>} [content.components] An array of component objects
|
|
||||||
* @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only)
|
|
||||||
* @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only)
|
|
||||||
* @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2)
|
|
||||||
* @arg {String} [content.components[].label] The label to be displayed in the component (type 2)
|
|
||||||
* @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1)
|
|
||||||
* @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1)
|
|
||||||
* @arg {Array<Object>} [content.components[].options] The options for this component (type 3 only)
|
|
||||||
* @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected
|
|
||||||
* @arg {String} [content.components[].options[].description] The description for this option
|
|
||||||
* @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option
|
|
||||||
* @arg {String} content.components[].options[].label The label for this option
|
|
||||||
* @arg {Number | String} content.components[].options[].value The value for this option
|
|
||||||
* @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only)
|
|
||||||
* @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required
|
|
||||||
* @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu
|
|
||||||
* @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only)
|
|
||||||
* @arg {String} content.content A content string
|
|
||||||
* @arg {Boolean} [content.disableEveryone] Whether to filter @everyone/@here or not (overrides default)
|
|
||||||
* @arg {Array<Object>} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure
|
|
||||||
* @arg {Number} [content.flags] A number representing the flags to apply to the message. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for flags reference
|
|
||||||
* @returns {Promise<Message>}
|
|
||||||
*/
|
|
||||||
async editMessage(messageID: string, content: MessageContentEdit) {
|
|
||||||
return await this.client.editMessage.call(this.client, this.id, messageID, content)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all invites in the channel
|
|
||||||
* @returns {Promise<Array<Invite>>}
|
|
||||||
*/
|
|
||||||
async getInvites() {
|
|
||||||
return await this.client.getChannelInvites.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a previous message in the channel
|
|
||||||
* @arg {String} messageID The ID of the message
|
|
||||||
* @returns {Promise<Message>}
|
|
||||||
*/
|
|
||||||
async getMessage(messageID: string) {
|
|
||||||
return await this.client.getMessage.call(this.client, this.id, messageID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of users who reacted with a specific reaction
|
|
||||||
* @arg {String} messageID The ID of the message
|
|
||||||
* @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji)
|
|
||||||
* @arg {Object} [options] Options for the request. If this is a number, it is treated as `options.limit` ([DEPRECATED] behavior)
|
|
||||||
* @arg {Number} [options.limit=100] The maximum number of users to get
|
|
||||||
* @arg {String} [options.after] Get users after this user ID
|
|
||||||
* @returns {Promise<Array<User>>}
|
|
||||||
*/
|
|
||||||
async getMessageReaction(messageID: string, reaction: string, options: GetMessageReactionOptions) {
|
|
||||||
return await this.client.getMessageReaction.call(this.client, this.id, messageID, reaction, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get previous messages in the channel
|
|
||||||
* @arg {Object} [options] Options for the request. If this is a number ([DEPRECATED] behavior), it is treated as `options.limit`
|
|
||||||
* @arg {String} [options.after] Get messages after this message ID
|
|
||||||
* @arg {String} [options.around] Get messages around this message ID (does not work with limit > 100)
|
|
||||||
* @arg {String} [options.before] Get messages before this message ID
|
|
||||||
* @arg {Number} [options.limit=50] The max number of messages to get
|
|
||||||
* @returns {Promise<Array<Message>>}
|
|
||||||
*/
|
|
||||||
async getMessages(options: GetMessagesOptions) {
|
|
||||||
return await this.client.getMessages.call(this.client, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Purge previous messages in the channel with an optional filter (bot accounts only)
|
|
||||||
* @arg {Object} options Options for the request. If this is a number ([DEPRECATED] behavior), it is treated as `options.limit`
|
|
||||||
* @arg {String} [options.after] Get messages after this message ID
|
|
||||||
* @arg {String} [options.before] Get messages before this message ID
|
|
||||||
* @arg {Function} [options.filter] Optional filter function that returns a boolean when passed a Message object
|
|
||||||
* @arg {Number} options.limit The max number of messages to search through, -1 for no limit
|
|
||||||
* @arg {String} [options.reason] The reason to be displayed in audit logs
|
|
||||||
* @returns {Promise<Number>} Resolves with the number of messages deleted
|
|
||||||
*/
|
|
||||||
async purge(options: PurgeChannelOptions) {
|
|
||||||
return await this.client.purgeChannel.call(this.client, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a reaction from a message
|
|
||||||
* @arg {String} messageID The ID of the message
|
|
||||||
* @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji)
|
|
||||||
* @arg {String} [userID="@me"] The ID of the user to remove the reaction for
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async removeMessageReaction(messageID: string, reaction: string, userID: string) {
|
|
||||||
return await this.client.removeMessageReaction.call(this.client, this.id, messageID, reaction, userID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all reactions from a message for a single emoji
|
|
||||||
* @arg {String} messageID The ID of the message
|
|
||||||
* @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji)
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async removeMessageReactionEmoji(messageID: string, reaction: string) {
|
|
||||||
return await this.client.removeMessageReactionEmoji.call(this.client, this.id, messageID, reaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all reactions from a message
|
|
||||||
* @arg {String} messageID The ID of the message
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async removeMessageReactions(messageID: string) {
|
|
||||||
return await this.client.removeMessageReactions.call(this.client, this.id, messageID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send typing status in the channel
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async sendTyping() {
|
|
||||||
return await this.client.sendChannelTyping.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON(['lastMessageID', 'messages', 'rateLimitPerUser', ...props])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TextVoiceChannel
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
/* eslint-disable no-useless-call */
|
|
||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
import type { DiscordChannel } from '@discordeno/types'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
import Collection from '../../Collection.js'
|
|
||||||
import type { CreateInviteOptions, TextVoiceChannelTypes, VideoQualityMode } from '../../typings.js'
|
|
||||||
import type Member from '../guilds/Member.js'
|
|
||||||
import GuildChannel from './Guild.js'
|
|
||||||
|
|
||||||
export class VoiceChannel extends GuildChannel {
|
|
||||||
bitrate: number = 0
|
|
||||||
rtcRegion: string | null = null
|
|
||||||
type: TextVoiceChannelTypes = 0
|
|
||||||
userLimit: number = 0
|
|
||||||
videoQualityMode: VideoQualityMode = 0
|
|
||||||
voiceMembers: Collection<string, Member>
|
|
||||||
|
|
||||||
constructor(data: DiscordChannel, client: Client) {
|
|
||||||
super(data, client)
|
|
||||||
|
|
||||||
this.voiceMembers = new Collection()
|
|
||||||
this.update(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
update(data: DiscordChannel): void {
|
|
||||||
super.update(data)
|
|
||||||
|
|
||||||
if (data.bitrate !== undefined) {
|
|
||||||
this.bitrate = data.bitrate
|
|
||||||
}
|
|
||||||
if (data.rtc_region !== undefined) {
|
|
||||||
this.rtcRegion = data.rtc_region
|
|
||||||
}
|
|
||||||
if (data.user_limit !== undefined) {
|
|
||||||
this.userLimit = data.user_limit
|
|
||||||
}
|
|
||||||
if (data.video_quality_mode !== undefined) {
|
|
||||||
this.videoQualityMode = data.video_quality_mode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an invite for the channel
|
|
||||||
* @arg {Object} [options] Invite generation options
|
|
||||||
* @arg {Number} [options.maxAge] How long the invite should last in seconds
|
|
||||||
* @arg {Number} [options.maxUses] How many uses the invite should last for
|
|
||||||
* @arg {Boolean} [options.temporary] Whether the invite grants temporary membership or not
|
|
||||||
* @arg {Boolean} [options.unique] Whether the invite is unique or not
|
|
||||||
* @arg {String} [reason] The reason to be displayed in audit logs
|
|
||||||
* @returns {Promise<Invite>}
|
|
||||||
*/
|
|
||||||
async createInvite(options: CreateInviteOptions, reason: string) {
|
|
||||||
return await this.client.createChannelInvite.call(this.client, this.id, options, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all invites in the channel
|
|
||||||
* @returns {Promise<Array<Invite>>}
|
|
||||||
*/
|
|
||||||
async getInvites() {
|
|
||||||
return await this.client.getChannelInvites.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: gateway
|
|
||||||
// /**
|
|
||||||
// * Joins the channel.
|
|
||||||
// * @arg {Object} [options] VoiceConnection constructor options
|
|
||||||
// * @arg {Object} [options.opusOnly] Skip opus encoder initialization. You should not enable this unless you know what you are doing
|
|
||||||
// * @arg {Object} [options.shared] Whether the VoiceConnection will be part of a SharedStream or not
|
|
||||||
// * @arg {Boolean} [options.selfMute] Whether the bot joins the channel muted or not
|
|
||||||
// * @arg {Boolean} [options.selfDeaf] Whether the bot joins the channel deafened or not
|
|
||||||
// * @returns {Promise<VoiceConnection>} Resolves with a VoiceConnection
|
|
||||||
// */
|
|
||||||
// join(options: JoinVoiceChannelOptions) {
|
|
||||||
// return this.client.joinVoiceChannel.call(this.client, this.id, options);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO: gateway
|
|
||||||
// /**
|
|
||||||
// * Leaves the channel.
|
|
||||||
// */
|
|
||||||
// leave() {
|
|
||||||
// return this.client.leaveVoiceChannel.call(this.client, this.id);
|
|
||||||
// }
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON(['bitrate', 'rtcRegion', 'userLimit', 'videoQualityMode', 'voiceMembers', ...props])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default VoiceChannel
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
/* eslint-disable no-useless-call */
|
|
||||||
import type { DiscordThreadMember } from '@discordeno/types'
|
|
||||||
import Base from '../../../Base.js'
|
|
||||||
import type Client from '../../../Client.js'
|
|
||||||
import type Member from '../../guilds/Member.js'
|
|
||||||
|
|
||||||
export class ThreadMember extends Base {
|
|
||||||
client: Client
|
|
||||||
/** The user-thread settings of this member */
|
|
||||||
flags: number
|
|
||||||
/** The ID of the thread this member is a part of */
|
|
||||||
threadID: string
|
|
||||||
/** Timestamp of when the member joined the thread */
|
|
||||||
joinTimestamp: number
|
|
||||||
/** The guild member that this thread member belongs to. This will never be present when fetching over REST */
|
|
||||||
guildMember?: Member
|
|
||||||
|
|
||||||
constructor(data: DiscordThreadMember, client: Client) {
|
|
||||||
super(data.user_id)
|
|
||||||
|
|
||||||
this.client = client
|
|
||||||
this.flags = data.flags
|
|
||||||
this.threadID = data.id
|
|
||||||
this.joinTimestamp = Date.parse(data.join_timestamp)
|
|
||||||
}
|
|
||||||
|
|
||||||
get _client(): Client {
|
|
||||||
return this.client
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Remove the member from the thread */
|
|
||||||
async leave(): Promise<void> {
|
|
||||||
return await this._client.leaveThread.call(this._client, this.threadID, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON(['threadID', 'joinTimestamp', ...props])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ThreadMember
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import ThreadChannel from './Thread.js'
|
|
||||||
|
|
||||||
export class NewsThreadChannel extends ThreadChannel {}
|
|
||||||
|
|
||||||
export default NewsThreadChannel
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import type { DiscordChannel } from '@discordeno/types'
|
|
||||||
import type Client from '../../../Client.js'
|
|
||||||
import ThreadChannel from './Thread.js'
|
|
||||||
|
|
||||||
export class PrivateThreadChannel extends ThreadChannel {
|
|
||||||
constructor(data: DiscordChannel, client: Client, messageLimit?: number) {
|
|
||||||
super(data, client, messageLimit)
|
|
||||||
|
|
||||||
this.update(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
update(data: DiscordChannel): void {
|
|
||||||
if (data.thread_metadata !== undefined) {
|
|
||||||
this.threadMetadata = {
|
|
||||||
archiveTimestamp: Date.parse(data.thread_metadata.archive_timestamp),
|
|
||||||
archived: data.thread_metadata.archived,
|
|
||||||
autoArchiveDuration: data.thread_metadata.auto_archive_duration,
|
|
||||||
invitable: data.thread_metadata.invitable,
|
|
||||||
locked: data.thread_metadata.locked,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PrivateThreadChannel
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import ThreadChannel from './Thread.js'
|
|
||||||
|
|
||||||
export class PublicThreadChannel extends ThreadChannel {}
|
|
||||||
|
|
||||||
export default PublicThreadChannel
|
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
/* eslint-disable no-useless-call */
|
|
||||||
import type { BigString, DiscordChannel, GetMessagesOptions } from '@discordeno/types'
|
|
||||||
import type Client from '../../../Client.js'
|
|
||||||
import Collection from '../../../Collection.js'
|
|
||||||
import type { FileContent, GetMessageReactionOptions, MessageContent, MessageContentEdit, PurgeChannelOptions } from '../../../typings.js'
|
|
||||||
import type Message from '../../Message.js'
|
|
||||||
import type User from '../../users/User.js'
|
|
||||||
import GuildChannel from '../Guild.js'
|
|
||||||
import ThreadMember from './Member.js'
|
|
||||||
|
|
||||||
export class ThreadChannel extends GuildChannel {
|
|
||||||
/** The cached messages that were sent in this channel. */
|
|
||||||
messages: Collection<BigString, Message>
|
|
||||||
/** The cached thread members that are in this channel. */
|
|
||||||
members: Collection<BigString, ThreadMember>
|
|
||||||
/** The id of the last message in this channel. */
|
|
||||||
lastMessageID: string
|
|
||||||
/** The id of the user who created this thread. */
|
|
||||||
ownerID: string
|
|
||||||
/** The approximate amount of members that have joined this thread. */
|
|
||||||
memberCount?: number
|
|
||||||
/** The approximate amount of messages in this channel. */
|
|
||||||
messageCount?: number
|
|
||||||
/** The rate limit that users can send messages in this channel. 0 means no rate limit has been enabled. */
|
|
||||||
rateLimitPerUser?: number
|
|
||||||
/** The data relevant to this thread. */
|
|
||||||
threadMetadata?: {
|
|
||||||
/** Timestamp when the thread's archive status was last changed, used for calculating recent activity */
|
|
||||||
archiveTimestamp: number
|
|
||||||
/** Whether the thread is archived. */
|
|
||||||
archived: boolean
|
|
||||||
/** Duration in minutes to automatically archive the thread after recent activity, either 60, 1440, 4320 or 10080 */
|
|
||||||
autoArchiveDuration: number
|
|
||||||
/** Whether the thread is locked. */
|
|
||||||
locked: boolean
|
|
||||||
/** Whether or not the thread is inviteable. */
|
|
||||||
invitable?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The bot's thread member object if it has joined the thread. */
|
|
||||||
member?: ThreadMember
|
|
||||||
|
|
||||||
constructor(data: DiscordChannel, client: Client, messageLimit?: number) {
|
|
||||||
super(data, client)
|
|
||||||
|
|
||||||
this.members = new Collection()
|
|
||||||
this.messages = new Collection()
|
|
||||||
|
|
||||||
this.messages.limit = messageLimit ?? client.options.messageLimit
|
|
||||||
this.lastMessageID = data.last_message_id ?? ""
|
|
||||||
this.ownerID = data.owner_id!
|
|
||||||
|
|
||||||
this.update(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
update(data: DiscordChannel): void {
|
|
||||||
super.update(data)
|
|
||||||
|
|
||||||
if (data.member_count !== undefined) {
|
|
||||||
this.memberCount = data.member_count
|
|
||||||
}
|
|
||||||
if (data.message_count !== undefined) {
|
|
||||||
this.messageCount = data.message_count
|
|
||||||
}
|
|
||||||
if (data.rate_limit_per_user !== undefined) {
|
|
||||||
this.rateLimitPerUser = data.rate_limit_per_user
|
|
||||||
}
|
|
||||||
if (data.thread_metadata !== undefined) {
|
|
||||||
this.threadMetadata = {
|
|
||||||
archiveTimestamp: Date.parse(data.thread_metadata.archive_timestamp),
|
|
||||||
archived: data.thread_metadata.archived,
|
|
||||||
autoArchiveDuration: data.thread_metadata.auto_archive_duration,
|
|
||||||
locked: data.thread_metadata.locked,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (data.member !== undefined) {
|
|
||||||
this.member = new ThreadMember(data.member, this.client)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async addMessageReaction(messageID: BigString, reaction: string): Promise<void> {
|
|
||||||
return await this.client.addMessageReaction.call(this.client, this.id, messageID, reaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
async createMessage(content: MessageContent, file?: FileContent | FileContent[]) {
|
|
||||||
return await this.client.createMessage.call(this.client, this.id, content, file)
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteMessage(messageID: BigString, reason?: string): Promise<void> {
|
|
||||||
return await this.client.deleteMessage.call(this.client, this.id, messageID, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteMessages(messageIDs: BigString[], reason?: string): Promise<void> {
|
|
||||||
return await this.client.deleteMessages.call(this.client, this.id, messageIDs, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
async editMessage(messageID: BigString, content: MessageContentEdit) {
|
|
||||||
return await this.client.editMessage.call(this.client, this.id, messageID, content)
|
|
||||||
}
|
|
||||||
|
|
||||||
async getMembers(): Promise<ThreadMember[]> {
|
|
||||||
return await this.client.getThreadMembers.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
async getMessage(messageID: BigString): Promise<Message> {
|
|
||||||
return await this.client.getMessage.call(this.client, this.id, messageID)
|
|
||||||
}
|
|
||||||
|
|
||||||
async getMessageReaction(messageID: BigString, reaction: string, options?: GetMessageReactionOptions): Promise<User[]> {
|
|
||||||
return await this.client.getMessageReaction.call(this.client, this.id, messageID, reaction, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
async getMessages(options: GetMessagesOptions) {
|
|
||||||
return await this.client.getMessages.call(this.client, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPins(): Promise<Message[]> {
|
|
||||||
return await this.client.getPins.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
async join(userID: BigString = '@me'): Promise<void> {
|
|
||||||
return await this.client.joinThread.call(this.client, this.id, userID)
|
|
||||||
}
|
|
||||||
|
|
||||||
async leave(userID: BigString): Promise<void> {
|
|
||||||
return await this.client.leaveThread.call(this.client, this.id, userID)
|
|
||||||
}
|
|
||||||
|
|
||||||
async pinMessage(messageID: BigString): Promise<void> {
|
|
||||||
return await this.client.pinMessage.call(this.client, this.id, messageID)
|
|
||||||
}
|
|
||||||
|
|
||||||
async purge(options: PurgeChannelOptions): Promise<number> {
|
|
||||||
return await this.client.purgeChannel.call(this.client, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
async removeMessageReaction(messageID: BigString, reaction: string, userID: BigString = '@me') {
|
|
||||||
return await this.client.removeMessageReaction.call(this.client, this.id, messageID, reaction, userID)
|
|
||||||
}
|
|
||||||
|
|
||||||
async removeMessageReactionEmoji(messageID: BigString, reaction: string): Promise<void> {
|
|
||||||
return await this.client.removeMessageReactionEmoji.call(this.client, this.id, messageID, reaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
async removeMessageReactions(messageID: BigString): Promise<void> {
|
|
||||||
return await this.client.removeMessageReactions.call(this.client, this.id, messageID)
|
|
||||||
}
|
|
||||||
|
|
||||||
async sendTyping(): Promise<void> {
|
|
||||||
return await this.client.sendChannelTyping.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
async unpinMessage(messageID: BigString): Promise<void> {
|
|
||||||
return await this.client.unpinMessage.call(this.client, this.id, messageID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use deleteMessage instead
|
|
||||||
*/
|
|
||||||
async unsendMessage(messageID: BigString): Promise<void> {
|
|
||||||
return await this.client.deleteMessage.call(this.client, this.id, messageID)
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON([
|
|
||||||
'lastMessageID',
|
|
||||||
'memberCount',
|
|
||||||
'messageCount',
|
|
||||||
'messages',
|
|
||||||
'ownerID',
|
|
||||||
'rateLimitPerUser',
|
|
||||||
'threadMetadata',
|
|
||||||
'member',
|
|
||||||
...props,
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ThreadChannel
|
|
||||||
@@ -1,181 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
import type { DiscordAuditLogChange, DiscordAuditLogEntry } from '@discordeno/types'
|
|
||||||
import { AuditLogEvents } from '@discordeno/types'
|
|
||||||
import Base from '../../Base.js'
|
|
||||||
import type GuildChannel from '../channels/Guild.js'
|
|
||||||
import type TextChannel from '../channels/Text.js'
|
|
||||||
import Invite from '../Invite.js'
|
|
||||||
import type Message from '../Message.js'
|
|
||||||
import type User from '../users/User.js'
|
|
||||||
import type Guild from './Guild.js'
|
|
||||||
import type Member from './Member.js'
|
|
||||||
import type Role from './Role.js'
|
|
||||||
|
|
||||||
export class GuildAuditLogEntry extends Base {
|
|
||||||
/** The guild to which this entry belongs. */
|
|
||||||
guild: Guild
|
|
||||||
/** The action type of the entry. */
|
|
||||||
actionType: AuditLogEvents
|
|
||||||
/** The reason for the action. */
|
|
||||||
reason: string | null
|
|
||||||
/** The user that performed the action. */
|
|
||||||
user?: User
|
|
||||||
/** The properties of the targeted object before the action was taken. For example, if a channel was renamed from #general to #potato, this would be `{name: "general"}`` */
|
|
||||||
before: Record<DiscordAuditLogChange['key'], DiscordAuditLogChange['old_value']>
|
|
||||||
|
|
||||||
/** The properties of the targeted object after the action was taken. For example, if a channel was renamed from #general to #potato, this would be `{name: "potato"}`` */
|
|
||||||
after: Record<DiscordAuditLogChange['key'], DiscordAuditLogChange['new_value']>
|
|
||||||
|
|
||||||
/** The ID of the action target */
|
|
||||||
targetID?: string
|
|
||||||
/** The number of entities targeted. For example, for action type 26 (MEMBER_MOVE), this is the number of members that were moved/disconnected from the voice channel */
|
|
||||||
count?: number
|
|
||||||
/** The channel targeted in the entry, action types 26 (MEMBER_MOVE), 72/74/75 (MESSAGE_DELETE/PIN/UNPIN) and 83/84/85 (STAGE_INSTANCE_CREATE/UPDATE/DELETE) only */
|
|
||||||
channel?: GuildChannel
|
|
||||||
/** The message that was (un)pinned, action types 74/75 (MESSAGE_PIN/UNPIN) only. If the message is not cached, this will be an object with an `id` key. No other property is guaranteed. */
|
|
||||||
message?: Message | { id: string }
|
|
||||||
/** The number of days of inactivity to prune for, action type 21 (MEMBER_PRUNE) only */
|
|
||||||
deleteMemberDays?: number
|
|
||||||
/** The number of members pruned from the server, action type 21 (MEMBER_PRUNE) only */
|
|
||||||
membersRemoved?: number
|
|
||||||
/** The member described by the permission overwrite, action types 13-15 (CHANNEL\_OVERWRITE\_CREATE/UPDATE/DELETE) only. If the member is not cached, this could be {id: String} */
|
|
||||||
member?: Member | { id: string }
|
|
||||||
/** The role described by the permission overwrite, action types 13-15 (CHANNEL\_OVERWRITE\_CREATE/UPDATE/DELETE) only. If the role is not cached, this could be {id: String, name: String} */
|
|
||||||
role?: Role | { id: string; name: string }
|
|
||||||
|
|
||||||
constructor(data: DiscordAuditLogEntry, guild: Guild) {
|
|
||||||
super(data.id)
|
|
||||||
|
|
||||||
this.guild = guild
|
|
||||||
this.actionType = data.action_type
|
|
||||||
this.reason = data.reason ?? null
|
|
||||||
this.user = data.user_id ? guild.client.users.get(data.user_id) : undefined
|
|
||||||
this.before = {} as any
|
|
||||||
this.after = {} as any
|
|
||||||
if (data.changes) {
|
|
||||||
data.changes.forEach((change) => {
|
|
||||||
if (change.old_value !== undefined) {
|
|
||||||
this.before[change.key] = change.old_value
|
|
||||||
}
|
|
||||||
if (change.new_value !== undefined) {
|
|
||||||
this.after[change.key] = change.new_value
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.target_id) {
|
|
||||||
this.targetID = data.target_id
|
|
||||||
}
|
|
||||||
if (data.options) {
|
|
||||||
if (data.options.count) {
|
|
||||||
this.count = +data.options.count
|
|
||||||
}
|
|
||||||
if (data.options.channel_id) {
|
|
||||||
if (this.actionType >= 83) {
|
|
||||||
this.channel = guild.threads.get(data.options.channel_id)
|
|
||||||
} else {
|
|
||||||
this.channel = guild.channels.get(data.options.channel_id)
|
|
||||||
}
|
|
||||||
if (data.options.message_id) {
|
|
||||||
this.message = (this.channel && (this.channel as TextChannel).messages.get(data.options.message_id)) ?? {
|
|
||||||
id: data.options.message_id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (data.options.delete_member_days) {
|
|
||||||
this.deleteMemberDays = +data.options.delete_member_days
|
|
||||||
this.membersRemoved = +data.options.members_removed
|
|
||||||
}
|
|
||||||
if (data.options.type) {
|
|
||||||
if (data.options.type === '1') {
|
|
||||||
this.member = guild.members.get(data.options.id) ?? {
|
|
||||||
id: data.options.id,
|
|
||||||
}
|
|
||||||
} else if (data.options.type === '0') {
|
|
||||||
this.role = guild.roles.get(data.options.id) ?? {
|
|
||||||
id: data.options.id,
|
|
||||||
name: data.options.role_name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get target() {
|
|
||||||
// pay more, get less
|
|
||||||
if (this.actionType < 10) {
|
|
||||||
// Guild
|
|
||||||
return this.guild
|
|
||||||
} else if (this.actionType < 20) {
|
|
||||||
// Channel
|
|
||||||
return this.guild?.channels.get(this.targetID!)
|
|
||||||
} else if (this.actionType < 30) {
|
|
||||||
// Member
|
|
||||||
if (this.actionType === AuditLogEvents.MemberMove || this.actionType === AuditLogEvents.MemberDisconnect) {
|
|
||||||
// MEMBER_MOVE / MEMBER_DISCONNECT
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return this.guild?.members.get(this.targetID!)
|
|
||||||
} else if (this.actionType < 40) {
|
|
||||||
// Role
|
|
||||||
return this.guild?.roles.get(this.targetID!)
|
|
||||||
} else if (this.actionType < 50) {
|
|
||||||
// Invite
|
|
||||||
const changes = this.actionType === 42 ? this.before : this.after // Apparently the meaning of life is a deleted invite
|
|
||||||
return new Invite(
|
|
||||||
{
|
|
||||||
code: changes.code as string,
|
|
||||||
// @ts-expect-error idk why this is happening
|
|
||||||
channel: changes.channel,
|
|
||||||
guild: this.guild.toJSON(),
|
|
||||||
uses: changes.uses as number,
|
|
||||||
max_uses: changes.max_uses as number,
|
|
||||||
max_age: changes.max_age as number,
|
|
||||||
temporary: changes.temporary as boolean,
|
|
||||||
},
|
|
||||||
this.guild?.client,
|
|
||||||
)
|
|
||||||
} else if (this.actionType < 60) {
|
|
||||||
// Webhook
|
|
||||||
return null // Go get the webhook yourself
|
|
||||||
} else if (this.actionType < 70) {
|
|
||||||
// Emoji
|
|
||||||
return this.guild?.emojis?.find((emoji) => emoji.id === this.targetID)
|
|
||||||
} else if (this.actionType < 80) {
|
|
||||||
// Message
|
|
||||||
return this.guild?.client.users.get(this.targetID!)
|
|
||||||
} else if (this.actionType < 83) {
|
|
||||||
// Integrations
|
|
||||||
return null
|
|
||||||
} else if (this.actionType < 90) {
|
|
||||||
// Stage Instances
|
|
||||||
return this.guild?.threads.get(this.targetID!)
|
|
||||||
} else if (this.actionType < 100) {
|
|
||||||
// Sticker
|
|
||||||
return this.guild?.stickers?.find((sticker) => sticker.id === this.targetID)
|
|
||||||
} else {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
|
||||||
throw new Error('Unrecognized action type: ' + this.actionType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON([
|
|
||||||
'actionType',
|
|
||||||
'after',
|
|
||||||
'before',
|
|
||||||
'channel',
|
|
||||||
'count',
|
|
||||||
'deleteMemberDays',
|
|
||||||
'member',
|
|
||||||
'membersRemoved',
|
|
||||||
'reason',
|
|
||||||
'role',
|
|
||||||
'targetID',
|
|
||||||
'user',
|
|
||||||
...props,
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default GuildAuditLogEntry
|
|
||||||
@@ -1,952 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
/* eslint-disable no-useless-call */
|
|
||||||
import {
|
|
||||||
BitwisePermissionFlags,
|
|
||||||
ChannelTypes,
|
|
||||||
type ApplicationCommandTypes,
|
|
||||||
type BigString,
|
|
||||||
type DefaultMessageNotificationLevels,
|
|
||||||
type DiscordEmoji,
|
|
||||||
type DiscordGuild,
|
|
||||||
type DiscordMemberWithUser,
|
|
||||||
type DiscordSticker,
|
|
||||||
type ExplicitContentFilterLevels,
|
|
||||||
type GuildFeatures,
|
|
||||||
type GuildNsfwLevel,
|
|
||||||
type MfaLevels,
|
|
||||||
type PremiumTiers,
|
|
||||||
type RequestGuildMembers,
|
|
||||||
type SystemChannelFlags,
|
|
||||||
type VerificationLevels,
|
|
||||||
} from '@discordeno/types'
|
|
||||||
import Base from '../../Base.js'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
import type { ImageFormat, ImageSize } from '../../Client.js'
|
|
||||||
import Collection from '../../Collection.js'
|
|
||||||
import { BANNER, GUILD_DISCOVERY_SPLASH, GUILD_ICON, GUILD_SPLASH } from '../../Endpoints.js'
|
|
||||||
import type Shard from '../../gateway/Shard.js'
|
|
||||||
import type {
|
|
||||||
AnyGuildChannel,
|
|
||||||
AnyThreadChannel,
|
|
||||||
ApplicationCommand,
|
|
||||||
ApplicationCommandPermissions,
|
|
||||||
ApplicationCommandStructure,
|
|
||||||
ChannelPosition,
|
|
||||||
CreateChannelOptions,
|
|
||||||
CreateStickerOptions,
|
|
||||||
DiscoveryMetadata,
|
|
||||||
DiscoveryOptions,
|
|
||||||
DiscoverySubcategoryResponse,
|
|
||||||
EditStickerOptions,
|
|
||||||
Emoji,
|
|
||||||
EmojiOptions,
|
|
||||||
GetGuildAuditLogOptions,
|
|
||||||
GetGuildBansOptions,
|
|
||||||
GetPruneOptions,
|
|
||||||
GetRESTGuildMembersOptions,
|
|
||||||
GuildApplicationCommandPermissions,
|
|
||||||
GuildAuditLog,
|
|
||||||
GuildBan,
|
|
||||||
GuildOptions,
|
|
||||||
GuildTemplateOptions,
|
|
||||||
GuildVanity,
|
|
||||||
IntegrationOptions,
|
|
||||||
ListedGuildThreads,
|
|
||||||
MemberOptions,
|
|
||||||
PruneMemberOptions,
|
|
||||||
RoleOptions,
|
|
||||||
Sticker,
|
|
||||||
VoiceRegion,
|
|
||||||
VoiceStateOptions,
|
|
||||||
Webhook,
|
|
||||||
WelcomeScreen,
|
|
||||||
WelcomeScreenOptions,
|
|
||||||
Widget,
|
|
||||||
WidgetData,
|
|
||||||
} from '../../typings.js'
|
|
||||||
import { generateChannelFrom } from '../../utils/generate.js'
|
|
||||||
import type CategoryChannel from '../channels/Category.js'
|
|
||||||
import type GuildChannel from '../channels/Guild.js'
|
|
||||||
import type StageChannel from '../channels/Stage.js'
|
|
||||||
import type TextChannel from '../channels/Text.js'
|
|
||||||
import type TextVoiceChannel from '../channels/TextVoice.js'
|
|
||||||
import type ThreadChannel from '../channels/threads/Thread.js'
|
|
||||||
import type VoiceChannel from '../channels/Voice.js'
|
|
||||||
import type Invite from '../Invite.js'
|
|
||||||
import Permission from '../Permission.js'
|
|
||||||
import User from '../users/User.js'
|
|
||||||
import type GuildIntegration from './Integration.js'
|
|
||||||
import Member from './Member.js'
|
|
||||||
import Role from './Role.js'
|
|
||||||
import StageInstance from './StageInstance.js'
|
|
||||||
import type GuildTemplate from './Template.js'
|
|
||||||
import type { VoiceState } from './VoiceState.js'
|
|
||||||
|
|
||||||
export class Guild extends Base {
|
|
||||||
/** The client object */
|
|
||||||
client: Client
|
|
||||||
/** The id of the guild owner. */
|
|
||||||
ownerID: string
|
|
||||||
/** The id of the application. */
|
|
||||||
applicationID?: string | null
|
|
||||||
/** The id of the widget channel. */
|
|
||||||
widgetChannelID?: string | null
|
|
||||||
/** The afk channel id if one is set. */
|
|
||||||
afkChannelID?: string | null
|
|
||||||
/** The system channel id if one is set. */
|
|
||||||
systemChannelID?: string | null
|
|
||||||
/** The public updates channel id if one is set. */
|
|
||||||
publicUpdatesChannelID?: string | null
|
|
||||||
/** The rules channel id if one is set. */
|
|
||||||
rulesChannelID?: string | null
|
|
||||||
/** The name of the guild. */
|
|
||||||
name?: string
|
|
||||||
/** The description of the guild. */
|
|
||||||
description?: string | null
|
|
||||||
/** The vanity url if one is set. */
|
|
||||||
vanityURL?: string | null
|
|
||||||
/** The preferred locale of the server. */
|
|
||||||
preferredLocale?: string
|
|
||||||
/** The system channel flags. */
|
|
||||||
systemChannelFlags?: SystemChannelFlags
|
|
||||||
/** The verification level of the guild. */
|
|
||||||
verificationLevel?: VerificationLevels
|
|
||||||
/** The default notification level. */
|
|
||||||
defaultNotifications?: DefaultMessageNotificationLevels
|
|
||||||
/** The explicit content filter setting for this guild. */
|
|
||||||
explicitContentFilter?: ExplicitContentFilterLevels
|
|
||||||
/** Array of guild features */
|
|
||||||
features: GuildFeatures[] = []
|
|
||||||
/** The premium tier of the guild. */
|
|
||||||
premiumTier?: PremiumTiers
|
|
||||||
/** The MFA level of the guild. */
|
|
||||||
mfaLevel?: MfaLevels
|
|
||||||
/** The NSFW level of the guild. */
|
|
||||||
nsfwLevel?: GuildNsfwLevel
|
|
||||||
/** The compressed form of the guild splash image. */
|
|
||||||
_splash?: bigint
|
|
||||||
/** The compressed form of the guild's discovery splash image. */
|
|
||||||
_discoverySplash?: bigint
|
|
||||||
/** The compressed form of the guild's banner image. */
|
|
||||||
_banner?: bigint
|
|
||||||
/** The compressed form of the guild's icon image. */
|
|
||||||
_icon?: bigint
|
|
||||||
/** The cached emojis in the guild. */
|
|
||||||
emojis?: DiscordEmoji[]
|
|
||||||
/** The cached stickers in the guild. */
|
|
||||||
stickers?: DiscordSticker[]
|
|
||||||
/** The afk timeout in seconds. */
|
|
||||||
afkTimeout?: number
|
|
||||||
/** When this guild was joined at. */
|
|
||||||
joinedAt: number
|
|
||||||
/** The amount of members in the guild. */
|
|
||||||
memberCount: number
|
|
||||||
/** The approximate member count in the guild. */
|
|
||||||
approximateMemberCount?: number
|
|
||||||
/** The approximate presence count in the guild. */
|
|
||||||
approximatePresenceCount?: number
|
|
||||||
/** The amount of subscribers to the server. */
|
|
||||||
premiumSubscriptionCount?: number
|
|
||||||
/** The maximum amount of presences that can be in a guild. */
|
|
||||||
maxPresences?: number | null
|
|
||||||
/** The maximum amount of members that can be in the guild. */
|
|
||||||
maxMembers?: number
|
|
||||||
/** The maximum amount of members that can be in a video channel. */
|
|
||||||
maxVideoChannelUsers?: number | null
|
|
||||||
/** Whether or not this guild is unavailable. */
|
|
||||||
unavailable: boolean
|
|
||||||
/** Whether or not the widget is enabled in this guild. */
|
|
||||||
widgetEnabled: boolean
|
|
||||||
/** Whether or not this guild is considered large. */
|
|
||||||
large?: boolean
|
|
||||||
/** Whether or not the premium progress bar is enabled. */
|
|
||||||
premiumProgressBarEnabled?: boolean
|
|
||||||
/** Whether or not this server is nsfw. */
|
|
||||||
nsfw?: boolean
|
|
||||||
/** The welcome screen settings. */
|
|
||||||
welcomeScreen?: {
|
|
||||||
description: string | null
|
|
||||||
welcomeChannels?: Array<{
|
|
||||||
channelID: string
|
|
||||||
description: string
|
|
||||||
emojiID: string | null
|
|
||||||
emojiName: string | null
|
|
||||||
}>
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The cached members in this guild. */
|
|
||||||
members = new Collection<BigString, Member>()
|
|
||||||
/** The cached roles in this guild. */
|
|
||||||
roles = new Collection<BigString, Role>()
|
|
||||||
/** The cached channels in this guild. */
|
|
||||||
channels = new Collection<BigString, GuildChannel>()
|
|
||||||
/** The cached threads in this guild. */
|
|
||||||
threads = new Collection<BigString, ThreadChannel>()
|
|
||||||
/** The cached voice states in this guild. */
|
|
||||||
voiceStates = new Collection<BigString, VoiceState>()
|
|
||||||
/** The cached stage instances in this guild. */
|
|
||||||
stageInstances = new Collection<BigString, StageInstance>()
|
|
||||||
/** The shard that manages this guild. */
|
|
||||||
shard: Shard;
|
|
||||||
|
|
||||||
constructor(data: DiscordGuild, client: Client) {
|
|
||||||
super(data.id)
|
|
||||||
this.client = client
|
|
||||||
this.shard = client.shards.get(client.guildShardMap[this.id] || (Base.getDiscordEpoch(data.id) % (client.options.maxShards as number)) || 0)!;
|
|
||||||
|
|
||||||
this.ownerID = data.owner_id
|
|
||||||
|
|
||||||
this.unavailable = !!data.unavailable
|
|
||||||
this.joinedAt = Date.parse(data.joined_at!)
|
|
||||||
this.memberCount = data.member_count ?? 0
|
|
||||||
this.applicationID = data.application_id
|
|
||||||
this.widgetEnabled = !!data.widget_enabled
|
|
||||||
|
|
||||||
if (data.widget_channel_id !== undefined) {
|
|
||||||
this.widgetChannelID = data.widget_channel_id
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.approximate_member_count !== undefined) {
|
|
||||||
this.approximateMemberCount = data.approximate_member_count
|
|
||||||
}
|
|
||||||
if (data.approximate_presence_count !== undefined) {
|
|
||||||
this.approximatePresenceCount = data.approximate_presence_count
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.roles) {
|
|
||||||
for (const r of data.roles) {
|
|
||||||
const role = new Role(r, this)
|
|
||||||
this.roles.set(role.id, role)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.channels) {
|
|
||||||
for (const channelData of data.channels) {
|
|
||||||
channelData.guild_id = this.id.toString()
|
|
||||||
const channel = generateChannelFrom(channelData, client) as GuildChannel
|
|
||||||
this.channels.set(channel.id, channel)
|
|
||||||
client._channelGuildMap.set(channel.id, this.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.threads) {
|
|
||||||
for (const threadData of data.threads) {
|
|
||||||
threadData.guild_id = this.id.toString()
|
|
||||||
const thread = generateChannelFrom(threadData, client) as unknown as ThreadChannel
|
|
||||||
this.threads.set(thread.id, thread)
|
|
||||||
client._threadGuildMap.set(thread.id, this.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.members) {
|
|
||||||
for (const m of data.members) {
|
|
||||||
const member = new Member(m as DiscordMemberWithUser, this, client)
|
|
||||||
this.members.set(member.id, member)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.stage_instances) {
|
|
||||||
for (const stageInstance of data.stage_instances) {
|
|
||||||
stageInstance.guild_id = this.id
|
|
||||||
|
|
||||||
const instance = new StageInstance(stageInstance, client)
|
|
||||||
this.stageInstances.set(instance.id, instance)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.presences) {
|
|
||||||
for (const presence of data.presences) {
|
|
||||||
if (presence.user?.id) {
|
|
||||||
const cached = this.client.users.get(presence.user.id)
|
|
||||||
if (cached) cached.update(presence.user)
|
|
||||||
else {
|
|
||||||
const user = new User(presence.user, this.client)
|
|
||||||
this.client.users.set(user.id, user)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.voice_states) {
|
|
||||||
for (const voiceState of data.voice_states) {
|
|
||||||
if (!this.members.get(voiceState.user_id)) continue
|
|
||||||
|
|
||||||
if (voiceState.member) {
|
|
||||||
const member = new Member(voiceState.member, this, client)
|
|
||||||
this.members.set(member.id, member)
|
|
||||||
const user = new User(voiceState.member.user, client)
|
|
||||||
this.client.users.set(user.id, user)
|
|
||||||
|
|
||||||
// TODO: check channel type maybe voice channel?
|
|
||||||
;(this.channels.get(voiceState.channel_id!) as VoiceChannel)?.voiceMembers.set(member.id, member)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: voice support
|
|
||||||
// if (
|
|
||||||
// client.options.seedVoiceConnections &&
|
|
||||||
// voiceState.user_id === client.id &&
|
|
||||||
// !client.voiceConnections.get(this.id)
|
|
||||||
// ) {
|
|
||||||
// process.nextTick(() =>
|
|
||||||
// this.client.joinVoiceChannel(voiceState.channel_id)
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.update(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated - please use .client
|
|
||||||
*/
|
|
||||||
get _client() {
|
|
||||||
return this.client
|
|
||||||
}
|
|
||||||
|
|
||||||
update(data: DiscordGuild) {
|
|
||||||
if (data.name !== undefined) {
|
|
||||||
this.name = data.name
|
|
||||||
}
|
|
||||||
if (data.verification_level !== undefined) {
|
|
||||||
this.verificationLevel = data.verification_level
|
|
||||||
}
|
|
||||||
if (data.splash !== undefined) {
|
|
||||||
this._splash = data.splash ? this.client.iconHashToBigInt(data.splash) : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.discovery_splash !== undefined) {
|
|
||||||
this._discoverySplash = data.discovery_splash ? this.client.iconHashToBigInt(data.discovery_splash) : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.banner !== undefined) {
|
|
||||||
this._banner = data.banner ? this.client.iconHashToBigInt(data.banner) : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.owner_id !== undefined) {
|
|
||||||
this.ownerID = data.owner_id
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.icon !== undefined) {
|
|
||||||
this._icon = data.icon ? this.client.iconHashToBigInt(data.icon) : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: compress features.
|
|
||||||
if (data.features !== undefined) {
|
|
||||||
this.features = data.features
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.emojis !== undefined) {
|
|
||||||
this.emojis = data.emojis
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.stickers !== undefined) {
|
|
||||||
this.stickers = data.stickers
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.afk_channel_id !== undefined) {
|
|
||||||
this.afkChannelID = data.afk_channel_id
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.afk_timeout !== undefined) {
|
|
||||||
this.afkTimeout = data.afk_timeout
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.default_message_notifications !== undefined) {
|
|
||||||
this.defaultNotifications = data.default_message_notifications
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.mfa_level !== undefined) {
|
|
||||||
this.mfaLevel = data.mfa_level
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.large !== undefined) {
|
|
||||||
this.large = data.large
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.max_presences !== undefined) {
|
|
||||||
this.maxPresences = data.max_presences
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.explicit_content_filter !== undefined) {
|
|
||||||
this.explicitContentFilter = data.explicit_content_filter
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.system_channel_id !== undefined) {
|
|
||||||
this.systemChannelID = data.system_channel_id
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.system_channel_flags !== undefined) {
|
|
||||||
this.systemChannelFlags = data.system_channel_flags
|
|
||||||
}
|
|
||||||
if (data.premium_progress_bar_enabled !== undefined) {
|
|
||||||
this.premiumProgressBarEnabled = data.premium_progress_bar_enabled
|
|
||||||
}
|
|
||||||
if (data.premium_tier !== undefined) {
|
|
||||||
this.premiumTier = data.premium_tier
|
|
||||||
}
|
|
||||||
if (data.premium_subscription_count !== undefined) {
|
|
||||||
this.premiumSubscriptionCount = data.premium_subscription_count
|
|
||||||
}
|
|
||||||
if (data.vanity_url_code !== undefined) {
|
|
||||||
this.vanityURL = data.vanity_url_code
|
|
||||||
}
|
|
||||||
if (data.preferred_locale !== undefined) {
|
|
||||||
this.preferredLocale = data.preferred_locale
|
|
||||||
}
|
|
||||||
if (data.description !== undefined) {
|
|
||||||
this.description = data.description
|
|
||||||
}
|
|
||||||
if (data.max_members !== undefined) {
|
|
||||||
this.maxMembers = data.max_members
|
|
||||||
}
|
|
||||||
if (data.public_updates_channel_id !== undefined) {
|
|
||||||
this.publicUpdatesChannelID = data.public_updates_channel_id
|
|
||||||
}
|
|
||||||
if (data.rules_channel_id !== undefined) {
|
|
||||||
this.rulesChannelID = data.rules_channel_id
|
|
||||||
}
|
|
||||||
if (data.max_video_channel_users !== undefined) {
|
|
||||||
this.maxVideoChannelUsers = data.max_video_channel_users
|
|
||||||
}
|
|
||||||
if (data.welcome_screen !== undefined) {
|
|
||||||
this.welcomeScreen = {
|
|
||||||
description: data.welcome_screen.description,
|
|
||||||
welcomeChannels: data.welcome_screen.welcome_channels?.map((c) => {
|
|
||||||
return {
|
|
||||||
channelID: c.channel_id,
|
|
||||||
description: c.description,
|
|
||||||
emojiID: c.emoji_id,
|
|
||||||
emojiName: c.emoji_name,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if (data.nsfw !== undefined) {
|
|
||||||
// this.nsfw = data.nsfw;
|
|
||||||
// }
|
|
||||||
if (data.nsfw_level !== undefined) {
|
|
||||||
this.nsfwLevel = data.nsfw_level
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get banner(): string | undefined {
|
|
||||||
return this._banner ? this.client.iconBigintToHash(this._banner) : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
get bannerURL(): string | null {
|
|
||||||
return this.banner ? this.client._formatImage(BANNER(this.id, this.banner)) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
get icon(): string | undefined {
|
|
||||||
return this._icon ? this.client.iconBigintToHash(this._icon) : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
get iconURL(): string | null {
|
|
||||||
return this.icon ? this.client._formatImage(GUILD_ICON(this.id, this.icon)) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
get splash(): string | undefined {
|
|
||||||
return this._splash ? this.client.iconBigintToHash(this._splash) : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
get splashURL(): string | null {
|
|
||||||
return this.splash ? this.client._formatImage(GUILD_SPLASH(this.id, this.splash)) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
get discoverySplash(): string | undefined {
|
|
||||||
return this._discoverySplash ? this.client.iconBigintToHash(this._discoverySplash) : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
get discoverySplashURL(): string | null {
|
|
||||||
return this.discoverySplash ? this.client._formatImage(GUILD_DISCOVERY_SPLASH(this.id, this.discoverySplash)) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Add a discovery subcategory */
|
|
||||||
async addDiscoverySubcategory(categoryID: BigString, reason?: string): Promise<DiscoverySubcategoryResponse> {
|
|
||||||
return await this.client.addGuildDiscoverySubcategory.call(this.client, this.id, categoryID, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Add a role to a guild member */
|
|
||||||
async addMemberRole(memberID: BigString, roleID: BigString, reason?: string): Promise<void> {
|
|
||||||
return await this.client.addGuildMemberRole.call(this.client, this.id, memberID, roleID, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Ban a user from the guild */
|
|
||||||
async banMember(userID: BigString, deleteMessageDays = 0, reason?: string): Promise<void> {
|
|
||||||
return await this.client.banGuildMember.call(this.client, this.id, userID, deleteMessageDays, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Bulk create/edit guild application commands */
|
|
||||||
async bulkEditCommands(commands: Array<ApplicationCommand<ApplicationCommandTypes>>): Promise<Array<ApplicationCommand<ApplicationCommandTypes>>> {
|
|
||||||
return await this.client.bulkEditGuildCommands.call(this.client, this.id, commands)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a channel in the guild */
|
|
||||||
async createChannel(
|
|
||||||
name: string,
|
|
||||||
type = ChannelTypes.GuildText,
|
|
||||||
options: CreateChannelOptions,
|
|
||||||
): Promise<CategoryChannel | TextChannel | TextVoiceChannel | StageChannel> {
|
|
||||||
return await this.client.createChannel.call(this.client, this.id, name, type as number, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a guild application command */
|
|
||||||
async createCommand(command: ApplicationCommandStructure): Promise<ApplicationCommand<ApplicationCommandTypes>> {
|
|
||||||
return await this.client.createGuildCommand.call(this.client, this.id, command)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a emoji in the guild */
|
|
||||||
async createEmoji(options: EmojiOptions, reason?: string): Promise<Emoji> {
|
|
||||||
return await this.client.createGuildEmoji.call(this.client, this.id, options, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a guild role */
|
|
||||||
async createRole(options: Role | RoleOptions, reason?: string): Promise<Role> {
|
|
||||||
return await this.client.createRole.call(this.client, this.id, options, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a guild sticker */
|
|
||||||
async createSticker(options: CreateStickerOptions, reason?: string): Promise<Sticker> {
|
|
||||||
return await this.client.createGuildSticker.call(this.client, this.id, options, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a template for this guild */
|
|
||||||
async createTemplate(name: string, description?: string): Promise<GuildTemplate> {
|
|
||||||
return await this.client.createGuildTemplate.call(this.client, this.id, name, description)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete the guild (bot user must be owner) */
|
|
||||||
async delete(): Promise<void> {
|
|
||||||
if (this.ownerID !== this.client.id) throw new Error('To delete a guild, the bot must be the owner of the guild.')
|
|
||||||
|
|
||||||
return await this.client.deleteGuild.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete a guild application command */
|
|
||||||
async deleteCommand(commandID: BigString): Promise<void> {
|
|
||||||
return await this.client.deleteGuildCommand.call(this.client, this.id, commandID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete a discovery subcategory */
|
|
||||||
async deleteDiscoverySubcategory(categoryID: BigString, reason?: string): Promise<void> {
|
|
||||||
return await this.client.deleteGuildDiscoverySubcategory.call(this.client, this.id, categoryID, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete a emoji in the guild */
|
|
||||||
async deleteEmoji(emojiID: BigString, reason?: string): Promise<void> {
|
|
||||||
return await this.client.deleteGuildEmoji.call(this.client, this.id, emojiID, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete a guild integration */
|
|
||||||
async deleteIntegration(integrationID: BigString): Promise<void> {
|
|
||||||
return await this.client.deleteGuildIntegration.call(this.client, this.id, integrationID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete a role */
|
|
||||||
async deleteRole(roleID: BigString, reason?: string): Promise<void> {
|
|
||||||
return await this.client.deleteRole.call(this.client, this.id, roleID, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete a guild sticker */
|
|
||||||
async deleteSticker(stickerID: BigString, reason?: string): Promise<void> {
|
|
||||||
return await this.client.deleteGuildSticker.call(this.client, this.id, stickerID, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete a guild template */
|
|
||||||
async deleteTemplate(code: string): Promise<void> {
|
|
||||||
return await this.client.deleteGuildTemplate.call(this.client, this.id, code)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the guild's banner with the given format and size */
|
|
||||||
dynamicBannerURL(format?: ImageFormat, size?: ImageSize): string | null {
|
|
||||||
return this.banner ? this.client._formatImage(BANNER(this.id, this.banner), format, size) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the guild's discovery splash with the given format and size */
|
|
||||||
dynamicDiscoverySplashURL(format?: ImageFormat, size?: ImageSize): string | null {
|
|
||||||
return this.discoverySplash ? this.client._formatImage(GUILD_DISCOVERY_SPLASH(this.id, this.discoverySplash), format, size) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the guild's icon with the given format and size */
|
|
||||||
dynamicIconURL(format?: ImageFormat, size?: ImageSize): string | null {
|
|
||||||
return this.icon ? this.client._formatImage(GUILD_ICON(this.id, this.icon), format, size) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the guild's splash with the given format and size */
|
|
||||||
dynamicSplashURL(format?: ImageFormat, size?: ImageSize): string | null {
|
|
||||||
return this.splash ? this.client._formatImage(GUILD_SPLASH(this.id, this.splash), format, size) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit the guild */
|
|
||||||
async edit(options: GuildOptions, reason?: string): Promise<Guild> {
|
|
||||||
return await this.client.editGuild.call(this.client, this.id, options, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit multiple channels' positions. Note that channel position numbers are grouped by type (category, text, voice), then sorted in ascending order (lowest number is on top). */
|
|
||||||
async editChannelPositions(channelPositions: ChannelPosition[]): Promise<void> {
|
|
||||||
return await this.client.editChannelPositions.call(this.client, this.id, channelPositions)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit a guild application command */
|
|
||||||
async editCommand(commandID: BigString, commands: ApplicationCommandStructure): Promise<ApplicationCommand<ApplicationCommandTypes>> {
|
|
||||||
return await this.client.editGuildCommand.call(this.client, this.id, commandID, commands)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Edits command permissions for a specific command in a guild.
|
|
||||||
* Note: You can only add up to 10 permission overwrites for a command.
|
|
||||||
*/
|
|
||||||
async editCommandPermissions(commandID: BigString, permissions: ApplicationCommandPermissions[]): Promise<GuildApplicationCommandPermissions> {
|
|
||||||
return await this.client.editCommandPermissions.call(this.client, this.id, commandID, permissions)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit the guild's discovery data */
|
|
||||||
async editDiscovery(options: DiscoveryOptions): Promise<DiscoveryMetadata> {
|
|
||||||
return await this.client.editGuildDiscovery.call(this.client, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Edit a emoji in the guild
|
|
||||||
* @arg {String} emojiID The ID of the emoji you want to modify
|
|
||||||
* @arg {Object} options Emoji options
|
|
||||||
* @arg {String} [options.name] The name of emoji
|
|
||||||
* @arg {Array} [options.roles] An array containing authorized role IDs
|
|
||||||
* @arg {String} [reason] The reason to be displayed in audit logs
|
|
||||||
* @returns {Promise<Object>} A guild emoji object
|
|
||||||
*/
|
|
||||||
async editEmoji(
|
|
||||||
emojiID: BigString,
|
|
||||||
options: {
|
|
||||||
name?: string | undefined
|
|
||||||
roles?: string[] | undefined
|
|
||||||
},
|
|
||||||
reason?: string,
|
|
||||||
): Promise<Emoji> {
|
|
||||||
return await this.client.editGuildEmoji.call(this.client, this.id, emojiID, options, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit a guild integration */
|
|
||||||
async editIntegration(integrationID: BigString, options: IntegrationOptions): Promise<void> {
|
|
||||||
return await this.client.editGuildIntegration.call(this.client, this.id, integrationID, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit a guild member */
|
|
||||||
async editMember(memberID: BigString, options: MemberOptions, reason?: string): Promise<Member> {
|
|
||||||
return await this.client.editGuildMember.call(this.client, this.id, memberID, options, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit the guild role */
|
|
||||||
async editRole(roleID: BigString, options: RoleOptions, reason?: string): Promise<Role> {
|
|
||||||
return await this.client.editRole.call(this.client, this.id, roleID, options, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit a guild sticker */
|
|
||||||
async editSticker(stickerID: BigString, options: EditStickerOptions, reason?: string): Promise<Sticker> {
|
|
||||||
return await this.client.editGuildSticker.call(this.client, this.id, stickerID, options, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit a guild template */
|
|
||||||
async editTemplate(code: string, options: GuildTemplateOptions): Promise<GuildTemplate> {
|
|
||||||
return await this.client.editGuildTemplate.call(this.client, this.id, code, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Modify the guild's vanity code */
|
|
||||||
async editVanity(code: string | null): Promise<unknown> {
|
|
||||||
return await this.client.editGuildVanity.call(this.client, this.id, code)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Update a user's voice state - See [caveats](https://discord.com/developers/docs/resources/guild#modify-user-voice-state-caveats) */
|
|
||||||
async editVoiceState(options: VoiceStateOptions, userID: BigString = '@me'): Promise<void> {
|
|
||||||
return await this.client.editGuildVoiceState.call(this.client, this.id, options, userID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit the guild welcome screen */
|
|
||||||
async editWelcomeScreen(options: WelcomeScreenOptions): Promise<WelcomeScreen> {
|
|
||||||
return await this.client.editGuildWelcomeScreen.call(this.client, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Modify a guild's widget */
|
|
||||||
async editWidget(options: Widget): Promise<Widget> {
|
|
||||||
return await this.client.editGuildWidget.call(this.client, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Request all guild members from Discord */
|
|
||||||
async fetchAllMembers(timeout?: number): Promise<number> {
|
|
||||||
return await this.fetchMembers({
|
|
||||||
guildId: this.id,
|
|
||||||
limit: 0,
|
|
||||||
}).then((m: any[]) => m.length)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Request specific guild members through the gateway connection */
|
|
||||||
async fetchMembers(options: RequestGuildMembers): Promise<Member[]> {
|
|
||||||
// TODO: Use gateway fetch
|
|
||||||
return await this.client.getRESTGuildMembers(this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get all active threads in this guild */
|
|
||||||
async getActiveThreads(): Promise<ListedGuildThreads<AnyThreadChannel>> {
|
|
||||||
return await this.client.getActiveGuildThreads.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the audit log for the guild */
|
|
||||||
async getAuditLog(options: GetGuildAuditLogOptions): Promise<GuildAuditLog> {
|
|
||||||
return await this.client.getGuildAuditLog.call(this.client, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a ban from the ban list of a guild */
|
|
||||||
async getBan(userID: BigString): Promise<GuildBan> {
|
|
||||||
return await this.client.getGuildBan.call(this.client, this.id, userID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the ban list of the guild */
|
|
||||||
async getBans(options?: GetGuildBansOptions): Promise<GuildBan[]> {
|
|
||||||
return await this.client.getGuildBans.call(this.client, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a guild application command */
|
|
||||||
async getCommand(commandID: BigString): Promise<ApplicationCommand<ApplicationCommandTypes>> {
|
|
||||||
return await this.client.getGuildCommand.call(this.client, this.id, commandID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the a guild's application command permissions */
|
|
||||||
async getCommandPermissions(commandID: BigString): Promise<GuildApplicationCommandPermissions> {
|
|
||||||
return await this.client.getCommandPermissions.call(this.client, this.id, commandID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the guild's application commands */
|
|
||||||
async getCommands(): Promise<ApplicationCommand<ApplicationCommandTypes>> {
|
|
||||||
return await this.client.getGuildCommands.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the guild's discovery object */
|
|
||||||
async getDiscovery(): Promise<DiscoveryMetadata> {
|
|
||||||
return await this.client.getGuildDiscovery.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the all of a guild's application command permissions */
|
|
||||||
async getGuildCommandPermissions(): Promise<GuildApplicationCommandPermissions[]> {
|
|
||||||
return await this.client.getGuildCommandPermissions.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a list of integrations for the guild */
|
|
||||||
async getIntegrations(): Promise<GuildIntegration[]> {
|
|
||||||
return await this.client.getGuildIntegrations.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get all invites in the guild */
|
|
||||||
async getInvites(): Promise<Invite[]> {
|
|
||||||
return await this.client.getGuildInvites.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the prune count for the guild */
|
|
||||||
async getPruneCount(options: GetPruneOptions): Promise<number> {
|
|
||||||
return await this.client.getPruneCount.call(this.client, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a guild's channels via the REST API. REST mode is required to use this endpoint. */
|
|
||||||
async getRESTChannels(): Promise<AnyGuildChannel[]> {
|
|
||||||
return await this.client.getRESTGuildChannels.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a guild emoji via the REST API. REST mode is required to use this endpoint. */
|
|
||||||
async getRESTEmoji(emojiID: BigString): Promise<Emoji> {
|
|
||||||
return await this.client.getRESTGuildEmoji.call(this.client, this.id, emojiID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a guild's emojis via the REST API. REST mode is required to use this endpoint. */
|
|
||||||
async getRESTEmojis(): Promise<Emoji[]> {
|
|
||||||
return await this.client.getRESTGuildEmojis.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a guild's members via the REST API. REST mode is required to use this endpoint. */
|
|
||||||
async getRESTMember(memberID: BigString): Promise<Member> {
|
|
||||||
return await this.client.getRESTGuildMember.call(this.client, this.id, memberID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a guild's members via the REST API. REST mode is required to use this endpoint. */
|
|
||||||
async getRESTMembers(options?: GetRESTGuildMembersOptions): Promise<Member[]> {
|
|
||||||
return await this.client.getRESTGuildMembers.call(this.client, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a guild's roles via the REST API. REST mode is required to use this endpoint. */
|
|
||||||
async getRESTRoles(): Promise<Role[]> {
|
|
||||||
return await this.client.getRESTGuildRoles.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a guild sticker via the REST API. REST mode is required to use this endpoint. */
|
|
||||||
async getRESTSticker(stickerID: BigString): Promise<Sticker> {
|
|
||||||
return await this.client.getRESTGuildSticker.call(this.client, this.id, stickerID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a guild's stickers via the REST API. REST mode is required to use this endpoint. */
|
|
||||||
async getRESTStickers(): Promise<Sticker[]> {
|
|
||||||
return await this.client.getRESTGuildStickers.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the guild's templates */
|
|
||||||
async getTemplates(): Promise<GuildTemplate[]> {
|
|
||||||
return await this.client.getGuildTemplates.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the vanity url of the guild */
|
|
||||||
async getVanity(): Promise<GuildVanity> {
|
|
||||||
return await this.client.getGuildVanity.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get possible voice regions for a guild */
|
|
||||||
async getVoiceRegions(): Promise<VoiceRegion[]> {
|
|
||||||
return await this.client.getVoiceRegions.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get all the webhooks in the guild */
|
|
||||||
async getWebhooks(): Promise<Webhook[]> {
|
|
||||||
return await this.client.getGuildWebhooks.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the welcome screen of the Community guild, shown to new members */
|
|
||||||
async getWelcomeScreen(): Promise<WelcomeScreen> {
|
|
||||||
return await this.client.getGuildWelcomeScreen.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a guild's widget object */
|
|
||||||
async getWidget(): Promise<WidgetData> {
|
|
||||||
return await this.client.getGuildWidget.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a guild's widget settings object */
|
|
||||||
async getWidgetSettings(): Promise<Widget> {
|
|
||||||
return await this.client.getGuildWidgetSettings.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Kick a member from the guild */
|
|
||||||
async kickMember(userID: BigString, reason?: string): Promise<void> {
|
|
||||||
return await this.client.kickGuildMember.call(this.client, this.id, userID, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Leave the guild */
|
|
||||||
async leave(): Promise<void> {
|
|
||||||
return await this.client.leaveGuild.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: gateway voice
|
|
||||||
// /** Leaves the voice channel in this guild */
|
|
||||||
// async leaveVoiceChannel(): Promise<void> {
|
|
||||||
// return await this.client.closeVoiceConnection.call(this.client, this.id);
|
|
||||||
// }
|
|
||||||
|
|
||||||
/** Get the guild permissions of a member */
|
|
||||||
permissionsOf(memberID: BigString | Member): Permission {
|
|
||||||
const member = ['string', 'bigint'].includes(typeof memberID) ? this.members.get(memberID as BigString)! : (memberID as Member)
|
|
||||||
if (member.id === this.ownerID) {
|
|
||||||
return new Permission(BitwisePermissionFlags.ADMINISTRATOR)
|
|
||||||
} else {
|
|
||||||
let permissions = this.roles.get(this.id)!.permissions.allow
|
|
||||||
if (permissions & BigInt(BitwisePermissionFlags.ADMINISTRATOR)) {
|
|
||||||
return new Permission(BitwisePermissionFlags.ADMINISTRATOR)
|
|
||||||
}
|
|
||||||
for (const id of member.roles) {
|
|
||||||
const role = this.roles.get(id)
|
|
||||||
if (!role) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
const { allow: perm } = role.permissions
|
|
||||||
if (perm & BigInt(BitwisePermissionFlags.ADMINISTRATOR)) {
|
|
||||||
permissions = BigInt(BitwisePermissionFlags.ADMINISTRATOR)
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
permissions |= perm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new Permission(permissions)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Begin pruning the guild */
|
|
||||||
async pruneMembers(options?: PruneMemberOptions): Promise<number> {
|
|
||||||
return await this.client.pruneMembers.call(this.client, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Remove a role from a guild member */
|
|
||||||
async removeMemberRole(memberID: BigString, roleID: BigString, reason?: string): Promise<void> {
|
|
||||||
return await this.client.removeGuildMemberRole.call(this.client, this.id, memberID, roleID, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Search for guild members by partial nickname/username */
|
|
||||||
async searchMembers(query: string, limit = 1): Promise<Member[]> {
|
|
||||||
return await this.client.searchGuildMembers.call(this.client, this.id, query, limit)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Force a guild integration to sync */
|
|
||||||
async syncIntegration(integrationID: BigString): Promise<void> {
|
|
||||||
return await this.client.syncGuildIntegration.call(this.client, this.id, integrationID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Force a guild template to sync */
|
|
||||||
async syncTemplate(code: string): Promise<GuildTemplate> {
|
|
||||||
return await this.client.syncGuildTemplate.call(this.client, this.id, code)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Unban a user from the guild */
|
|
||||||
async unbanMember(userID: BigString, reason?: string): Promise<void> {
|
|
||||||
return await this.client.unbanGuildMember.call(this.client, this.id, userID, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON([
|
|
||||||
'afkChannelID',
|
|
||||||
'afkTimeout',
|
|
||||||
'applicationID',
|
|
||||||
'approximateMemberCount',
|
|
||||||
'approximatePresenceCount',
|
|
||||||
'autoRemoved',
|
|
||||||
'banner',
|
|
||||||
'categories',
|
|
||||||
'channels',
|
|
||||||
'defaultNotifications',
|
|
||||||
'description',
|
|
||||||
'discoverySplash',
|
|
||||||
'emojiCount',
|
|
||||||
'emojis',
|
|
||||||
'explicitContentFilter',
|
|
||||||
'features',
|
|
||||||
'icon',
|
|
||||||
'joinedAt',
|
|
||||||
'keywords',
|
|
||||||
'large',
|
|
||||||
'maxMembers',
|
|
||||||
'maxPresences',
|
|
||||||
'maxVideoChannelUsers',
|
|
||||||
'memberCount',
|
|
||||||
'members',
|
|
||||||
'mfaLevel',
|
|
||||||
'name',
|
|
||||||
'ownerID',
|
|
||||||
'pendingVoiceStates',
|
|
||||||
'preferredLocale',
|
|
||||||
'premiumProgressBarEnabled',
|
|
||||||
'premiumSubscriptionCount',
|
|
||||||
'premiumTier',
|
|
||||||
'primaryCategory',
|
|
||||||
'primaryCategoryID',
|
|
||||||
'publicUpdatesChannelID',
|
|
||||||
'roles',
|
|
||||||
'rulesChannelID',
|
|
||||||
'splash',
|
|
||||||
'stickers',
|
|
||||||
'systemChannelFlags',
|
|
||||||
'systemChannelID',
|
|
||||||
'unavailable',
|
|
||||||
'vanityURL',
|
|
||||||
'verificationLevel',
|
|
||||||
'voiceStates',
|
|
||||||
'welcomeScreen',
|
|
||||||
'widgetChannelID',
|
|
||||||
'widgetEnabled',
|
|
||||||
...props,
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Guild
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
/* eslint-disable no-useless-call */
|
|
||||||
import type { DiscordIntegration, DiscordIntegrationApplication } from '@discordeno/types'
|
|
||||||
import Base from '../../Base.js'
|
|
||||||
import type { IntegrationOptions } from '../../typings.js'
|
|
||||||
import User from '../users/User.js'
|
|
||||||
import type Guild from './Guild.js'
|
|
||||||
|
|
||||||
export class GuildIntegration extends Base {
|
|
||||||
/** The guild where this integration exists. */
|
|
||||||
guild: Guild
|
|
||||||
/** The name of the integration. */
|
|
||||||
name: string
|
|
||||||
/** The type of integration. */
|
|
||||||
type: string
|
|
||||||
/** The user connected to the integration. */
|
|
||||||
user?: User
|
|
||||||
/** Whether the integration is syncing or not. */
|
|
||||||
syncing?: boolean
|
|
||||||
/** THe Unix timestamp of last integration sync. */
|
|
||||||
syncedAt?: number
|
|
||||||
/** The number of subscribers. */
|
|
||||||
subscriberCount?: number
|
|
||||||
/** The role id of the role connected to the integration. */
|
|
||||||
roleID?: string
|
|
||||||
/** WHether or not the application was revoked. */
|
|
||||||
revoked?: boolean
|
|
||||||
/** Whether integration emoticons are enabled or not. */
|
|
||||||
enableEmoticons?: boolean
|
|
||||||
/** Behavior of expired subscriptions */
|
|
||||||
expireBehavior?: number
|
|
||||||
/** Grace period for expired subscriptions. */
|
|
||||||
expireGracePeriod?: number
|
|
||||||
/** Whether the integration is enabled or not. */
|
|
||||||
enabled?: boolean
|
|
||||||
/** The bot/oauth2 application for integration. */
|
|
||||||
application?: DiscordIntegrationApplication
|
|
||||||
|
|
||||||
/** Info on the integration account */
|
|
||||||
account: {
|
|
||||||
/** The id of the integration account. */
|
|
||||||
id: string
|
|
||||||
/** The name of the integration account. */
|
|
||||||
name: string
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(data: DiscordIntegration, guild: Guild) {
|
|
||||||
super(data.id)
|
|
||||||
|
|
||||||
this.guild = guild
|
|
||||||
this.name = data.name
|
|
||||||
this.type = data.type
|
|
||||||
|
|
||||||
if (data.role_id !== undefined) {
|
|
||||||
this.roleID = data.role_id
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.user) {
|
|
||||||
this.user = new User(data.user, guild.client)
|
|
||||||
guild.client.users.set(this.user.id, this.user)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.account = data.account // not worth making a class for
|
|
||||||
|
|
||||||
this.update(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
update(data: DiscordIntegration): void {
|
|
||||||
this.enabled = data.enabled
|
|
||||||
if (data.syncing !== undefined) {
|
|
||||||
this.syncing = data.syncing
|
|
||||||
}
|
|
||||||
if (data.expire_behavior !== undefined) {
|
|
||||||
this.expireBehavior = data.expire_behavior
|
|
||||||
}
|
|
||||||
if (data.expire_behavior !== undefined) {
|
|
||||||
this.expireGracePeriod = data.expire_grace_period
|
|
||||||
}
|
|
||||||
if (data.enable_emoticons) {
|
|
||||||
this.enableEmoticons = data.enable_emoticons
|
|
||||||
}
|
|
||||||
if (data.subscriber_count !== undefined) {
|
|
||||||
this.subscriberCount = data.subscriber_count
|
|
||||||
}
|
|
||||||
if (data.synced_at !== undefined) {
|
|
||||||
this.syncedAt = Date.parse(data.synced_at)
|
|
||||||
}
|
|
||||||
if (data.revoked !== undefined) {
|
|
||||||
this.revoked = data.revoked
|
|
||||||
}
|
|
||||||
if (data.application !== undefined) {
|
|
||||||
this.application = data.application
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete the guild integration */
|
|
||||||
async delete(): Promise<void> {
|
|
||||||
return await this.guild.client.deleteGuildIntegration.call(this.guild.client, this.guild.id, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit the guild integration */
|
|
||||||
async edit(options: IntegrationOptions): Promise<void> {
|
|
||||||
return await this.guild.client.editGuildIntegration.call(this.guild.client, this.guild.id, this.id, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Force the guild integration to sync */
|
|
||||||
async sync(): Promise<void> {
|
|
||||||
return await this.guild.client.syncGuildIntegration.call(this.guild.client, this.guild.id, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON([
|
|
||||||
'account',
|
|
||||||
'application',
|
|
||||||
'enabled',
|
|
||||||
'enableEmoticons',
|
|
||||||
'expireBehavior',
|
|
||||||
'expireGracePeriod',
|
|
||||||
'name',
|
|
||||||
'revoked',
|
|
||||||
'roleID',
|
|
||||||
'subscriberCount',
|
|
||||||
'syncedAt',
|
|
||||||
'syncing',
|
|
||||||
'type',
|
|
||||||
'user',
|
|
||||||
...props,
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default GuildIntegration
|
|
||||||
@@ -1,222 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/restrict-plus-operands */
|
|
||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
/* eslint-disable no-useless-call */
|
|
||||||
/* eslint-disable @typescript-eslint/return-await */
|
|
||||||
|
|
||||||
import type { BigString, DiscordMember, DiscordMemberWithUser } from '@discordeno/types'
|
|
||||||
import Base from '../../Base.js'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
import type { ImageFormat, ImageSize } from '../../Client.js'
|
|
||||||
import { GUILD_AVATAR } from '../../Endpoints.js'
|
|
||||||
import type { MemberOptions, Status } from '../../typings.js'
|
|
||||||
import User from '../users/User.js'
|
|
||||||
import type Guild from './Guild.js'
|
|
||||||
|
|
||||||
export class Member extends Base {
|
|
||||||
/** The client manager */
|
|
||||||
client: Client
|
|
||||||
/** An array of role IDs this member is a part of */
|
|
||||||
roles: string[]
|
|
||||||
/** The guild the member is in */
|
|
||||||
guild: Guild
|
|
||||||
/** The user object of the member */
|
|
||||||
user: User
|
|
||||||
/** The server nickname of the member. */
|
|
||||||
nick: string | null
|
|
||||||
/** The timestamp when this member joined the server. */
|
|
||||||
joinedAt?: number
|
|
||||||
/** Timestamp of when the member boosted the guild */
|
|
||||||
premiumSince?: number
|
|
||||||
/** Whether the user has not yet passed the guild's Membership Screening requirements */
|
|
||||||
pending?: boolean
|
|
||||||
/** Timestamp of timeout expiry. If `null`, the member is not timed out */
|
|
||||||
communicationDisabledUntil?: number | null
|
|
||||||
/** The members current status */
|
|
||||||
status?: Status;
|
|
||||||
|
|
||||||
/** The compressed form of the members avatar. */
|
|
||||||
_avatar?: bigint
|
|
||||||
|
|
||||||
constructor(data: (DiscordMember & { id: BigString }) | DiscordMemberWithUser, guild: Guild, client: Client) {
|
|
||||||
super(client.isDiscordMemberWithUser(data) ? data.user.id : data.id)
|
|
||||||
this.client = client
|
|
||||||
this.guild = guild
|
|
||||||
this.nick = null
|
|
||||||
this.roles = data.roles ?? []
|
|
||||||
|
|
||||||
const userID = client.isDiscordMemberWithUser(data) ? data.user.id : data.id
|
|
||||||
|
|
||||||
this.user = client.users.get(userID)!
|
|
||||||
if (data.user) {
|
|
||||||
this.user = new User(data.user, client)
|
|
||||||
client.users.set(this.user.id, this.user)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.user) {
|
|
||||||
throw new Error('User associated with Member not found: ' + userID)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.update(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
update(data: (DiscordMember & { id: BigString }) | DiscordMemberWithUser) {
|
|
||||||
if (data.joined_at !== undefined) {
|
|
||||||
this.joinedAt = data.joined_at ? Date.parse(data.joined_at) : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.premium_since !== undefined) {
|
|
||||||
this.premiumSince = data.premium_since === null ? undefined : Date.parse(data.premium_since)
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-prototype-builtins
|
|
||||||
if (data.hasOwnProperty('mute') && this.guild) {
|
|
||||||
// TODO: voice stuff
|
|
||||||
// const state = this.guild.voiceStates.get(this.id);
|
|
||||||
// if (
|
|
||||||
// data.channel_id === null &&
|
|
||||||
// !data.mute &&
|
|
||||||
// !data.deaf &&
|
|
||||||
// !data.suppress
|
|
||||||
// ) {
|
|
||||||
// this.guild.voiceStates.delete(this.id);
|
|
||||||
// } else if (state) {
|
|
||||||
// state.update(data);
|
|
||||||
// } else if (data.channel_id || data.mute || data.deaf || data.suppress) {
|
|
||||||
// this.guild.voiceStates.update(data);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.nick !== undefined) this.nick = data.nick
|
|
||||||
if (data.roles !== undefined) this.roles = data.roles
|
|
||||||
if (data.pending !== undefined) this.pending = data.pending
|
|
||||||
if (data.avatar !== undefined) this._avatar = data.avatar ? this.client.iconHashToBigInt(data.avatar) : undefined
|
|
||||||
|
|
||||||
if (data.communication_disabled_until !== undefined) {
|
|
||||||
if (data.communication_disabled_until !== null) {
|
|
||||||
this.communicationDisabledUntil = Date.parse(data.communication_disabled_until)
|
|
||||||
} else {
|
|
||||||
this.communicationDisabledUntil = data.communication_disabled_until
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get avatar(): string | undefined {
|
|
||||||
return this._avatar ? this.client.iconBigintToHash(this._avatar) : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
get accentColor() {
|
|
||||||
return this.user.accentColor
|
|
||||||
}
|
|
||||||
|
|
||||||
get avatarURL() {
|
|
||||||
return this.avatar ? this.client._formatImage(GUILD_AVATAR(this.guild.id, this.id, this.avatar)) : this.user.avatarURL
|
|
||||||
}
|
|
||||||
|
|
||||||
get banner() {
|
|
||||||
return this.user.banner
|
|
||||||
}
|
|
||||||
|
|
||||||
get bannerURL() {
|
|
||||||
return this.user.bannerURL
|
|
||||||
}
|
|
||||||
|
|
||||||
get bot() {
|
|
||||||
return this.user.bot
|
|
||||||
}
|
|
||||||
|
|
||||||
get createdAt() {
|
|
||||||
return this.user.createdAt
|
|
||||||
}
|
|
||||||
|
|
||||||
get defaultAvatar() {
|
|
||||||
return this.user.defaultAvatar
|
|
||||||
}
|
|
||||||
|
|
||||||
get defaultAvatarURL() {
|
|
||||||
return this.user.defaultAvatarURL
|
|
||||||
}
|
|
||||||
|
|
||||||
get discriminator() {
|
|
||||||
return this.user.discriminator
|
|
||||||
}
|
|
||||||
|
|
||||||
get mention() {
|
|
||||||
return `<@!${this.id}>`
|
|
||||||
}
|
|
||||||
|
|
||||||
get permissions() {
|
|
||||||
return this.guild.permissionsOf(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
get staticAvatarURL() {
|
|
||||||
return this.user.staticAvatarURL
|
|
||||||
}
|
|
||||||
|
|
||||||
get username() {
|
|
||||||
return this.user.username
|
|
||||||
}
|
|
||||||
|
|
||||||
get voiceState() {
|
|
||||||
if (this.guild?.voiceStates.has(this.id)) {
|
|
||||||
return this.guild.voiceStates.get(this.id)
|
|
||||||
} else {
|
|
||||||
// @ts-expect-error some eris magic at play here
|
|
||||||
return new VoiceState({ id: this.id })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Add a role to the guild member */
|
|
||||||
async addRole(roleID: BigString, reason?: string): Promise<void> {
|
|
||||||
return await this.client.addGuildMemberRole.call(this.client, this.guild.id, this.id, roleID, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Ban the user from the guild */
|
|
||||||
async ban(deleteMessageDays = 0, reason?: string): Promise<void> {
|
|
||||||
return await this.client.banGuildMember.call(this.client, this.guild.id, this.id, deleteMessageDays, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit the guild member */
|
|
||||||
async edit(options: MemberOptions, reason?: string): Promise<Member> {
|
|
||||||
return await this.client.editGuildMember.call(this.client, this.guild.id, this.id, options, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the member's avatar with the given format and size */
|
|
||||||
dynamicAvatarURL(format?: ImageFormat, size?: ImageSize): string {
|
|
||||||
return this.avatar
|
|
||||||
? this.client._formatImage(GUILD_AVATAR(this.guild.id, this.id, this.avatar), format, size)
|
|
||||||
: this.user.dynamicAvatarURL(format, size)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Kick the member from the guild */
|
|
||||||
async kick(reason?: string): Promise<void> {
|
|
||||||
return await this.client.kickGuildMember.call(this.client, this.guild.id, this.id, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Remove a role from the guild member */
|
|
||||||
async removeRole(roleID: BigString, reason?: string): Promise<void> {
|
|
||||||
return await this.client.removeGuildMemberRole.call(this.client, this.guild.id, this.id, roleID, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Unban the user from the guild */
|
|
||||||
async unban(reason?: string): Promise<void> {
|
|
||||||
return await this.client.unbanGuildMember.call(this.client, this.guild.id, this.id, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON([
|
|
||||||
'activities',
|
|
||||||
'communicationDisabledUntil',
|
|
||||||
'joinedAt',
|
|
||||||
'nick',
|
|
||||||
'pending',
|
|
||||||
'premiumSince',
|
|
||||||
'roles',
|
|
||||||
'status',
|
|
||||||
'user',
|
|
||||||
'voiceState',
|
|
||||||
...props,
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Member
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
import type { DiscordEmoji, DiscordGuildPreview } from '@discordeno/types'
|
|
||||||
import Base from '../../Base.js'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
import type { ImageFormat, ImageSize } from '../../Client.js'
|
|
||||||
import { GUILD_DISCOVERY_SPLASH, GUILD_ICON, GUILD_SPLASH } from '../../Endpoints.js'
|
|
||||||
import { GuildToggles } from '../toggles/Guild.js'
|
|
||||||
|
|
||||||
export class GuildPreview extends Base {
|
|
||||||
/** The client object */
|
|
||||||
client: Client
|
|
||||||
/** The name of the guild. */
|
|
||||||
name: string
|
|
||||||
/** The description of the guild. */
|
|
||||||
description: string | null
|
|
||||||
/** An array of guild emojis. */
|
|
||||||
emojis: DiscordEmoji[]
|
|
||||||
/** The approximate number of members in the guild. */
|
|
||||||
approximateMemberCount: number
|
|
||||||
/** The approximate number of presences in the guild. */
|
|
||||||
approximatePresenceCount: number
|
|
||||||
|
|
||||||
/** The guild's icon image url. */
|
|
||||||
_icon: bigint | null
|
|
||||||
/** The guild's splash image url. */
|
|
||||||
_splash: bigint | null
|
|
||||||
/** The guild's discovery splash image url. */
|
|
||||||
_discoverySplash: bigint | null
|
|
||||||
/** The guild's features. */
|
|
||||||
_features: GuildToggles
|
|
||||||
|
|
||||||
constructor(data: DiscordGuildPreview, client: Client) {
|
|
||||||
super(data.id)
|
|
||||||
|
|
||||||
this.client = client
|
|
||||||
this.name = data.name
|
|
||||||
this.description = data.description
|
|
||||||
this._icon = data.icon ? client.iconHashToBigInt(data.icon) : null
|
|
||||||
this._splash = data.splash ? client.iconHashToBigInt(data.splash) : null
|
|
||||||
this._discoverySplash = data.discovery_splash ? client.iconHashToBigInt(data.discovery_splash) : null
|
|
||||||
this.approximateMemberCount = data.approximate_member_count
|
|
||||||
this.approximatePresenceCount = data.approximate_presence_count
|
|
||||||
this.emojis = data.emojis
|
|
||||||
// TODO: make dd version accept a specific subset of discord guild here
|
|
||||||
// @ts-expect-error this should not cause an issue
|
|
||||||
this._features = new GuildToggles(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use .client
|
|
||||||
*/
|
|
||||||
get _client(): Client {
|
|
||||||
return this.client
|
|
||||||
}
|
|
||||||
|
|
||||||
get icon(): string | undefined {
|
|
||||||
return this._icon ? this.client.iconBigintToHash(this._icon) : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
get iconURL(): string | null {
|
|
||||||
return this.icon ? this.client._formatImage(GUILD_ICON(this.id, this.icon)) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
get splash(): string | undefined {
|
|
||||||
return this._splash ? this.client.iconBigintToHash(this._splash) : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
get splashURL(): string | null {
|
|
||||||
return this.splash ? this.client._formatImage(GUILD_SPLASH(this.id, this.splash)) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
get discoverySplash(): string | undefined {
|
|
||||||
return this._discoverySplash ? this.client.iconBigintToHash(this._discoverySplash) : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
get discoverySplashURL(): string | null {
|
|
||||||
return this.discoverySplash ? this.client._formatImage(GUILD_DISCOVERY_SPLASH(this.id, this.discoverySplash)) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
get features(): string[] {
|
|
||||||
return this._features.features.map((feature) => feature.replace(/([a-z])([A-Z])/, '$1_$2').toUpperCase())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the guild's splash with the given format and size */
|
|
||||||
dynamicDiscoverySplashURL(format?: ImageFormat, size?: ImageSize): string | null {
|
|
||||||
return this.discoverySplash ? this.client._formatImage(GUILD_DISCOVERY_SPLASH(this.id, this.discoverySplash), format, size) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the guild's icon with the given format and size */
|
|
||||||
dynamicIconURL(format?: ImageFormat, size?: ImageSize): string | null {
|
|
||||||
return this.icon ? this.client._formatImage(GUILD_ICON(this.id, this.icon), format, size) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the guild's splash with the given format and size */
|
|
||||||
dynamicSplashURL(format?: ImageFormat, size?: ImageSize): string | null {
|
|
||||||
return this.splash ? this.client._formatImage(GUILD_SPLASH(this.id, this.splash), format, size) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON([
|
|
||||||
'approximateMemberCount',
|
|
||||||
'approximatePresenceCount',
|
|
||||||
'description',
|
|
||||||
'discoverySplash',
|
|
||||||
'emojis',
|
|
||||||
'features',
|
|
||||||
'icon',
|
|
||||||
'name',
|
|
||||||
'splash',
|
|
||||||
...props,
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default GuildPreview
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
/* eslint-disable no-useless-call */
|
|
||||||
/* eslint-disable @typescript-eslint/return-await */
|
|
||||||
|
|
||||||
import type { DiscordRole, DiscordRoleTags } from '@discordeno/types'
|
|
||||||
import Base from '../../Base.js'
|
|
||||||
import { ROLE_ICON } from '../../Endpoints.js'
|
|
||||||
import type { RoleOptions } from '../../typings.js'
|
|
||||||
import Permission from '../Permission.js'
|
|
||||||
import type Guild from './Guild.js'
|
|
||||||
|
|
||||||
export class Role extends Base {
|
|
||||||
permissions: Permission
|
|
||||||
name: string
|
|
||||||
color: number
|
|
||||||
hoist: boolean
|
|
||||||
mentionable: boolean
|
|
||||||
managed: boolean
|
|
||||||
icon?: string
|
|
||||||
unicodeEmoji?: string
|
|
||||||
position: number
|
|
||||||
guild: Guild
|
|
||||||
tags?: Omit<DiscordRoleTags, 'premium_subscriber' | 'available_for_purchase' | 'guild_connections'> & {
|
|
||||||
premium_subscriber?: boolean
|
|
||||||
available_for_purchase?: boolean
|
|
||||||
guild_connections?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(data: DiscordRole, guild: Guild) {
|
|
||||||
super(data.id)
|
|
||||||
this.guild = guild
|
|
||||||
|
|
||||||
this.name = data.name
|
|
||||||
this.permissions = new Permission(data.permissions)
|
|
||||||
this.color = data.color
|
|
||||||
this.hoist = !!data.hoist
|
|
||||||
this.mentionable = !!data.mentionable
|
|
||||||
this.managed = !!data.managed
|
|
||||||
this.icon = data.icon
|
|
||||||
this.unicodeEmoji = data.unicode_emoji
|
|
||||||
this.position = data.position
|
|
||||||
this.tags = data.tags
|
|
||||||
? {
|
|
||||||
bot_id: data.tags.bot_id,
|
|
||||||
integration_id: data.tags.integration_id,
|
|
||||||
premium_subscriber: data.tags.premium_subscriber === null,
|
|
||||||
subscription_listing_id: data.tags.subscription_listing_id,
|
|
||||||
available_for_purchase: data.tags.available_for_purchase === null,
|
|
||||||
guild_connections: data.tags.guild_connections === null,
|
|
||||||
}
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
update(data: DiscordRole) {
|
|
||||||
if (data.name !== undefined) {
|
|
||||||
this.name = data.name
|
|
||||||
}
|
|
||||||
if (data.mentionable !== undefined) {
|
|
||||||
this.mentionable = data.mentionable
|
|
||||||
}
|
|
||||||
if (data.managed !== undefined) {
|
|
||||||
this.managed = data.managed
|
|
||||||
}
|
|
||||||
if (data.hoist !== undefined) {
|
|
||||||
this.hoist = data.hoist
|
|
||||||
}
|
|
||||||
if (data.color !== undefined) {
|
|
||||||
this.color = data.color
|
|
||||||
}
|
|
||||||
if (data.position !== undefined) {
|
|
||||||
this.position = data.position
|
|
||||||
}
|
|
||||||
if (data.permissions !== undefined) {
|
|
||||||
this.permissions = new Permission(data.permissions)
|
|
||||||
}
|
|
||||||
if (data.tags !== undefined) {
|
|
||||||
this.tags = {
|
|
||||||
bot_id: data.tags.bot_id,
|
|
||||||
integration_id: data.tags.integration_id,
|
|
||||||
subscription_listing_id: data.tags.subscription_listing_id,
|
|
||||||
available_for_purchase: data.tags.available_for_purchase === null,
|
|
||||||
premium_subscriber: data.tags.premium_subscriber === null,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (data.icon !== undefined) {
|
|
||||||
this.icon = data.icon
|
|
||||||
}
|
|
||||||
if (data.unicode_emoji !== undefined) {
|
|
||||||
this.unicodeEmoji = data.unicode_emoji
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get iconURL() {
|
|
||||||
return this.icon ? this.guild.client._formatImage(ROLE_ICON(this.id, this.icon)) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
get json() {
|
|
||||||
return this.permissions.json
|
|
||||||
}
|
|
||||||
|
|
||||||
get mention() {
|
|
||||||
return `<@&${this.id}>`
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete the role */
|
|
||||||
async delete(reason: string): Promise<void> {
|
|
||||||
return await this.guild.client.deleteRole.call(this.guild.client, this.guild.id, this.id, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit the guild role */
|
|
||||||
async edit(options: RoleOptions, reason?: string): Promise<Role> {
|
|
||||||
return await this.guild.client.editRole.call(this.guild.client, this.guild.id, this.id, options, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit the role's position. Note that role position numbers are highest on top and lowest at the bottom. */
|
|
||||||
async editPosition(position: number): Promise<void> {
|
|
||||||
return await this.guild.client.editRolePosition.call(this.guild.client, this.guild.id, this.id, position)
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON(['color', 'hoist', 'icon', 'managed', 'mentionable', 'name', 'permissions', 'position', 'tags', 'unicodeEmoji', ...props])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Role
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
/* eslint-disable no-useless-call */
|
|
||||||
import Base from '../../Base.js'
|
|
||||||
|
|
||||||
import type { DiscordStageInstance } from '@discordeno/types'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
import type { StageInstanceOptions } from '../../typings.js'
|
|
||||||
import type StageChannel from '../channels/Stage.js'
|
|
||||||
import type Guild from './Guild.js'
|
|
||||||
|
|
||||||
export class StageInstance extends Base {
|
|
||||||
/** The client manager. */
|
|
||||||
client: Client
|
|
||||||
/** The associated stage channel */
|
|
||||||
channel: StageChannel | { id: string }
|
|
||||||
/** The guild of the associated stage channel */
|
|
||||||
guild: Guild | { id: string }
|
|
||||||
/** The stage channel topic */
|
|
||||||
topic?: string | null
|
|
||||||
|
|
||||||
constructor(data: DiscordStageInstance, client: Client) {
|
|
||||||
super(data.id)
|
|
||||||
|
|
||||||
this.client = client
|
|
||||||
this.channel = client.getChannel(data.channel_id) ?? {
|
|
||||||
id: data.channel_id,
|
|
||||||
}
|
|
||||||
this.guild = client.guilds.get(data.guild_id) ?? { id: data.guild_id }
|
|
||||||
this.update(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use `.client` instead.
|
|
||||||
*/
|
|
||||||
get _client(): Client {
|
|
||||||
return this.client
|
|
||||||
}
|
|
||||||
|
|
||||||
update(data: DiscordStageInstance) {
|
|
||||||
if (data.topic !== undefined) {
|
|
||||||
this.topic = data.topic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete this stage instance */
|
|
||||||
async delete(): Promise<void> {
|
|
||||||
return await this.client.deleteStageInstance.call(this.client, this.channel.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Update this stage instance */
|
|
||||||
async edit(options: StageInstanceOptions): Promise<StageInstance> {
|
|
||||||
return await this.client.editStageInstance.call(this.client, this.channel.id, options)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default StageInstance
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
/* eslint-disable no-useless-call */
|
|
||||||
import type { DiscordTemplate } from '@discordeno/types'
|
|
||||||
import Base from '../../Base.js'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
import type { GuildTemplateOptions } from '../../typings.js'
|
|
||||||
import User from '../users/User.js'
|
|
||||||
import Guild from './Guild.js'
|
|
||||||
|
|
||||||
export class GuildTemplate {
|
|
||||||
/** The client class itself. */
|
|
||||||
client: Client
|
|
||||||
/** The template code (unique Id) */
|
|
||||||
code: string
|
|
||||||
/** Template name */
|
|
||||||
name: string
|
|
||||||
/** The description for the template */
|
|
||||||
description: string | null
|
|
||||||
/** Number of times this template has been used */
|
|
||||||
usageCount: number
|
|
||||||
/** The user who created the template */
|
|
||||||
creator: User
|
|
||||||
/** When this template was created */
|
|
||||||
createdAt: number
|
|
||||||
/** When this template was last synced to the source guild */
|
|
||||||
updatedAt: number
|
|
||||||
/** The guild snapshot this template contains */
|
|
||||||
serializedSourceGuild: Guild
|
|
||||||
/** The guild this template is based on. If the guild is not cached, this will be an object with `id` key. No other property is guaranteed */
|
|
||||||
sourceGuild: Guild | { id: string }
|
|
||||||
/** Whether the template has un-synced changes */
|
|
||||||
isDirty: boolean | null
|
|
||||||
|
|
||||||
constructor(data: DiscordTemplate, client: Client) {
|
|
||||||
this.client = client
|
|
||||||
this.code = data.code
|
|
||||||
this.createdAt = Date.parse(data.created_at)
|
|
||||||
this.creator = new User(data.creator, client)
|
|
||||||
this.client.users.set(this.creator.id, this.creator)
|
|
||||||
this.description = data.description
|
|
||||||
this.isDirty = data.is_dirty
|
|
||||||
this.name = data.name
|
|
||||||
this.sourceGuild = client.guilds.get(data.source_guild_id) ?? { id: data.source_guild_id }
|
|
||||||
this.updatedAt = Date.parse(data.updated_at)
|
|
||||||
this.usageCount = data.usage_count
|
|
||||||
|
|
||||||
data.serialized_source_guild.features = []
|
|
||||||
// @ts-expect-error Hacks to get this to not error
|
|
||||||
this.serializedSourceGuild = new Guild(data.serialized_source_guild, client)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use .client instead.
|
|
||||||
*/
|
|
||||||
get _client(): Client {
|
|
||||||
return this.client
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a guild based on this template. Only for bots in less than 10 guilds */
|
|
||||||
async createGuild(name: string, icon?: string): Promise<Guild> {
|
|
||||||
return await this.client.createGuildFromTemplate.call(this.client, this.code, name, icon)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete this template */
|
|
||||||
async delete(): Promise<void> {
|
|
||||||
return await this.client.deleteGuildTemplate.call(this.client, this.sourceGuild.id, this.code)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit this template */
|
|
||||||
async edit(options: GuildTemplateOptions): Promise<GuildTemplate> {
|
|
||||||
return await this.client.editGuildTemplate.call(this.client, this.sourceGuild.id, this.code, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Force this template to sync to the guild's current state */
|
|
||||||
async sync(): Promise<GuildTemplate> {
|
|
||||||
return await this.client.syncGuildTemplate.call(this.client, this.sourceGuild.id, this.code)
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return Base.prototype.toJSON.call(this, [
|
|
||||||
'code',
|
|
||||||
'createdAt',
|
|
||||||
'creator',
|
|
||||||
'description',
|
|
||||||
'isDirty',
|
|
||||||
'name',
|
|
||||||
'serializedSourceGuild',
|
|
||||||
'sourceGuild',
|
|
||||||
'updatedAt',
|
|
||||||
'usageCount',
|
|
||||||
...props,
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default GuildTemplate
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import type { DiscordUnavailableGuild } from '@discordeno/types'
|
|
||||||
import Base from '../../Base.js'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
|
|
||||||
export class UnavailableGuild extends Base {
|
|
||||||
/** Whether or not the guild is unavailable. */
|
|
||||||
unavailable: boolean
|
|
||||||
|
|
||||||
constructor(data: DiscordUnavailableGuild, client: Client) {
|
|
||||||
super(data.id)
|
|
||||||
|
|
||||||
// TODO: gateway
|
|
||||||
// this.shard = client.shards.get(client.guildShardMap[this.id]);
|
|
||||||
this.unavailable = !!data.unavailable
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON(['unavailable', ...props])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default UnavailableGuild
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
import type { DiscordVoiceState } from '@discordeno/types'
|
|
||||||
import Base from '../../Base.js'
|
|
||||||
import { VoiceStateToggle, VoiceStateToggles } from '../toggles/Voice.js'
|
|
||||||
|
|
||||||
export class VoiceState extends Base {
|
|
||||||
channelID: string | null = null
|
|
||||||
requestToSpeakTimestamp: number | null
|
|
||||||
sessionID!: string | null
|
|
||||||
|
|
||||||
bitfield: VoiceStateToggles
|
|
||||||
|
|
||||||
constructor(data: DiscordVoiceState & { id: string }) {
|
|
||||||
super(data.id)
|
|
||||||
|
|
||||||
this.requestToSpeakTimestamp = null
|
|
||||||
this.bitfield = new VoiceStateToggles(data)
|
|
||||||
|
|
||||||
this.update(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether or not the user is deafened by the server. */
|
|
||||||
get deaf(): boolean {
|
|
||||||
return this.bitfield.deaf
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set whether or not the user is deafened by the server. */
|
|
||||||
set deaf(value: boolean) {
|
|
||||||
if (value) this.bitfield.add(VoiceStateToggle.deaf)
|
|
||||||
else this.bitfield.remove(VoiceStateToggle.deaf)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether or not the user is muted by the server. */
|
|
||||||
get mute(): boolean {
|
|
||||||
return this.bitfield.mute
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set whether or not the user is muted by the server. */
|
|
||||||
set mute(value: boolean) {
|
|
||||||
if (value) this.bitfield.add(VoiceStateToggle.mute)
|
|
||||||
else this.bitfield.remove(VoiceStateToggle.mute)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether or not the user has deafened themself. */
|
|
||||||
get selfDeaf(): boolean {
|
|
||||||
return this.bitfield.selfDeaf
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set whether or not the user has deafened themself. */
|
|
||||||
set selfDeaf(value: boolean) {
|
|
||||||
if (value) this.bitfield.add(VoiceStateToggle.selfDeaf)
|
|
||||||
else this.bitfield.remove(VoiceStateToggle.selfDeaf)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether or not the user has muted themself. */
|
|
||||||
get selfMute(): boolean {
|
|
||||||
return this.bitfield.selfMute
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set whether or not the user has muted themself. */
|
|
||||||
set selfMute(value: boolean) {
|
|
||||||
if (value) this.bitfield.add(VoiceStateToggle.selfMute)
|
|
||||||
else this.bitfield.remove(VoiceStateToggle.selfMute)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether or not the user is streaming. */
|
|
||||||
get selfStream(): boolean {
|
|
||||||
return this.bitfield.selfStream
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set whether or not the user is streaming. */
|
|
||||||
set selfStream(value: boolean) {
|
|
||||||
if (value) this.bitfield.add(VoiceStateToggle.selfStream)
|
|
||||||
else this.bitfield.remove(VoiceStateToggle.selfStream)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether or not the user is video calling. */
|
|
||||||
get selfVideo(): boolean {
|
|
||||||
return this.bitfield.selfVideo
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set whether or not the user is video calling. */
|
|
||||||
set selfVideo(value: boolean) {
|
|
||||||
if (value) this.bitfield.add(VoiceStateToggle.selfVideo)
|
|
||||||
else this.bitfield.remove(VoiceStateToggle.selfVideo)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether or not the user is suppressed from speaking. */
|
|
||||||
get suppress(): boolean {
|
|
||||||
return this.bitfield.suppress
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set whether or not the user is suppressed from speaking. */
|
|
||||||
set suppress(value: boolean) {
|
|
||||||
if (value) this.bitfield.add(VoiceStateToggle.suppress)
|
|
||||||
else this.bitfield.remove(VoiceStateToggle.suppress)
|
|
||||||
}
|
|
||||||
|
|
||||||
update(data: DiscordVoiceState) {
|
|
||||||
if (data.channel_id !== undefined) {
|
|
||||||
this.channelID = data.channel_id
|
|
||||||
this.sessionID = data.channel_id === null ? null : data.session_id
|
|
||||||
} else if (this.channelID === undefined) {
|
|
||||||
this.channelID = this.sessionID = null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.mute !== undefined) this.mute = data.mute
|
|
||||||
if (data.deaf !== undefined) this.deaf = data.deaf
|
|
||||||
if (data.request_to_speak_timestamp) this.requestToSpeakTimestamp = Date.parse(data.request_to_speak_timestamp)
|
|
||||||
if (data.self_mute !== undefined) this.selfMute = data.self_mute
|
|
||||||
if (data.self_deaf !== undefined) this.selfDeaf = data.self_deaf
|
|
||||||
if (data.self_video !== undefined) this.selfVideo = data.self_video
|
|
||||||
if (data.self_stream !== undefined) this.selfStream = data.self_stream
|
|
||||||
if (data.suppress !== undefined) this.suppress = data.suppress
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON([
|
|
||||||
'channelID',
|
|
||||||
'deaf',
|
|
||||||
'mute',
|
|
||||||
'requestToSpeakTimestamp',
|
|
||||||
'selfDeaf',
|
|
||||||
'selfMute',
|
|
||||||
'selfStream',
|
|
||||||
'selfVideo',
|
|
||||||
'sessionID',
|
|
||||||
'suppress',
|
|
||||||
...props,
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/return-await */
|
|
||||||
/* eslint-disable no-useless-call */
|
|
||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
import type { DiscordInteraction, DiscordInteractionData } from '@discordeno/types'
|
|
||||||
import { InteractionResponseTypes } from '@discordeno/types'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
import type { ApplicationCommandOptionChoice } from '../../typings.js'
|
|
||||||
import type NewsChannel from '../channels/News.js'
|
|
||||||
import type PrivateChannel from '../channels/Private.js'
|
|
||||||
import type TextChannel from '../channels/Text.js'
|
|
||||||
import type Guild from '../guilds/Guild.js'
|
|
||||||
import Member from '../guilds/Member.js'
|
|
||||||
import Permission from '../Permission.js'
|
|
||||||
import User from '../users/User.js'
|
|
||||||
import Interaction from './Interaction.js'
|
|
||||||
|
|
||||||
export class AutocompleteInteraction extends Interaction {
|
|
||||||
/** The guild id if this interaction occurred in a guild. */
|
|
||||||
guildID?: string
|
|
||||||
/** The permissions the app or bot has within the channel, the interaction was sent from. */
|
|
||||||
appPermissions?: Permission
|
|
||||||
/** The channel id where this interaction was created in. */
|
|
||||||
channelID: string
|
|
||||||
/** The user who triggered the interaction. */
|
|
||||||
user: User
|
|
||||||
/** The data attached to this interaction. */
|
|
||||||
data?: DiscordInteractionData
|
|
||||||
/** The member who triggered the interaction. Sent when used in a guild. */
|
|
||||||
member?: Member
|
|
||||||
|
|
||||||
constructor(data: DiscordInteraction, client: Client) {
|
|
||||||
super(data, client)
|
|
||||||
|
|
||||||
this.channelID = data.channel_id!
|
|
||||||
this.data = data.data
|
|
||||||
|
|
||||||
if (data.guild_id !== undefined) {
|
|
||||||
this.guildID = data.guild_id
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.member !== undefined && this.guild) {
|
|
||||||
this.member = new Member(data.member, this.guild, this.client)
|
|
||||||
this.guild.members.set(this.member.id, this.member)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.user = new User(data.user ?? data.member!.user, this.client)
|
|
||||||
this.client.users.set(this.user.id, this.user)
|
|
||||||
|
|
||||||
if (data.app_permissions !== undefined) {
|
|
||||||
this.appPermissions = new Permission(data.app_permissions)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The channel the interaction was created in. */
|
|
||||||
get channel(): PrivateChannel | TextChannel | NewsChannel {
|
|
||||||
return this.client.getChannel(this.channelID) as PrivateChannel | TextChannel | NewsChannel
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The guild the interaction was created in. */
|
|
||||||
get guild(): Guild | undefined {
|
|
||||||
return this.guildID ? this.client.guilds.get(this.guildID) : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
async acknowledge(choices: ApplicationCommandOptionChoice[]) {
|
|
||||||
return await this.result(choices)
|
|
||||||
}
|
|
||||||
|
|
||||||
async result(choices: ApplicationCommandOptionChoice[]) {
|
|
||||||
if (this.acknowledged) throw new Error('You have already acknowledged this interaction.')
|
|
||||||
|
|
||||||
return this.client.createInteractionResponse
|
|
||||||
.call(this.client, this.id, this.token, {
|
|
||||||
type: InteractionResponseTypes.ApplicationCommandAutocompleteResult,
|
|
||||||
data: { choices },
|
|
||||||
})
|
|
||||||
.then(() => this.update())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AutocompleteInteraction
|
|
||||||
@@ -1,321 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/restrict-plus-operands */
|
|
||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
/* eslint-disable no-useless-call */
|
|
||||||
/* eslint-disable @typescript-eslint/return-await */
|
|
||||||
import { ApplicationCommandTypes, InteractionResponseTypes } from '@discordeno/types'
|
|
||||||
|
|
||||||
import Collection from '../../Collection.js'
|
|
||||||
import Channel from '../channels/Channel.js'
|
|
||||||
import Member from '../guilds/Member.js'
|
|
||||||
import Role from '../guilds/Role.js'
|
|
||||||
import Message from '../Message.js'
|
|
||||||
import User from '../users/User.js'
|
|
||||||
import Interaction from './Interaction.js'
|
|
||||||
|
|
||||||
import type {
|
|
||||||
BigString,
|
|
||||||
DiscordAttachment,
|
|
||||||
DiscordInteraction,
|
|
||||||
DiscordInteractionDataOption,
|
|
||||||
DiscordMessageComponents,
|
|
||||||
MessageComponentTypes,
|
|
||||||
} from '@discordeno/types'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
import type { AnyChannel, FileContent, InteractionContent, InteractionContentEdit } from '../../typings.js'
|
|
||||||
export class CommandInteraction extends Interaction {
|
|
||||||
name: string = "";
|
|
||||||
channel: AnyChannel
|
|
||||||
/** The type of component */
|
|
||||||
componentType?: MessageComponentTypes
|
|
||||||
/** The custom id provided for this component. */
|
|
||||||
customId?: string
|
|
||||||
/** The components if its a Modal Submit interaction. */
|
|
||||||
components?: DiscordMessageComponents
|
|
||||||
/** The values chosen by the user. */
|
|
||||||
values?: string[]
|
|
||||||
/** the type of the invoked command */
|
|
||||||
commandType: ApplicationCommandTypes = ApplicationCommandTypes.ChatInput
|
|
||||||
/** The Ids and Message objects */
|
|
||||||
messages = new Collection<BigString, Message>()
|
|
||||||
/** The Ids and User objects */
|
|
||||||
users = new Collection<BigString, User>()
|
|
||||||
/** The Ids and partial Member objects */
|
|
||||||
members = new Collection<BigString, Member>()
|
|
||||||
/** The Ids and Role objects */
|
|
||||||
roles = new Collection<BigString, Role>()
|
|
||||||
/** The Ids and partial Channel objects */
|
|
||||||
channels = new Collection<BigString, Channel>()
|
|
||||||
/** The ids and attachment objects */
|
|
||||||
attachments = new Collection<BigString, DiscordAttachment>()
|
|
||||||
/** The params + values from the user */
|
|
||||||
options?: DiscordInteractionDataOption[]
|
|
||||||
/** The target id if this is a context menu command. */
|
|
||||||
targetID?: string
|
|
||||||
/** the id of the guild the command is registered to */
|
|
||||||
guildID?: string
|
|
||||||
|
|
||||||
member?: Member
|
|
||||||
user: User
|
|
||||||
|
|
||||||
constructor(info: DiscordInteraction, client: Client) {
|
|
||||||
super(info, client)
|
|
||||||
|
|
||||||
this.channel = this.client.getChannel(info.channel_id!) ?? {
|
|
||||||
id: info.channel_id!,
|
|
||||||
}
|
|
||||||
|
|
||||||
// this.data = info.data!;
|
|
||||||
const guild = this.client.guilds.get(info.guild_id!)
|
|
||||||
|
|
||||||
if (info.data?.resolved !== undefined) {
|
|
||||||
// Users
|
|
||||||
if (info.data.resolved.users !== undefined) {
|
|
||||||
for (const u of Object.values(info.data.resolved.users)) {
|
|
||||||
const user = new User(u, this.client)
|
|
||||||
this.users.set(user.id, user)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Members
|
|
||||||
if (info.data.resolved.members !== undefined) {
|
|
||||||
for (const [, m] of Object.entries(info.data.resolved.members)) {
|
|
||||||
// @ts-expect-error some eris magic at play here
|
|
||||||
m.id = m
|
|
||||||
// @ts-expect-error some eris magic at play here
|
|
||||||
const member = new Member(m, guild, this.client)
|
|
||||||
this.members.set(member.id, member)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Roles
|
|
||||||
if (info.data.resolved.roles !== undefined) {
|
|
||||||
for (const r of Object.values(info.data.resolved.roles)) {
|
|
||||||
// @ts-expect-error some eris magic at play here
|
|
||||||
const role = new Role(r, guild)
|
|
||||||
this.roles.set(role.id, role)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Channels
|
|
||||||
if (info.data.resolved.channels !== undefined) {
|
|
||||||
for (const c of Object.values(info.data.resolved.channels)) {
|
|
||||||
const channel = new Channel(c, this.client)
|
|
||||||
this.channels.set(channel.id, channel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Messages
|
|
||||||
if (info.data.resolved.messages !== undefined) {
|
|
||||||
for (const m of Object.values(info.data.resolved.messages)) {
|
|
||||||
const message = new Message(m, this.client)
|
|
||||||
this.messages.set(message.id, message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attachments
|
|
||||||
if (info.data.resolved.attachments !== undefined) {
|
|
||||||
for (const attachment of Object.values(info.data.resolved.attachments)) {
|
|
||||||
this.attachments.set(attachment.id, attachment)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.guildID = info.guild_id
|
|
||||||
|
|
||||||
if (info.member !== undefined) {
|
|
||||||
// @ts-expect-error some eris magic at play here
|
|
||||||
this.member = new Member(info.member, guild, this.client)
|
|
||||||
guild?.members.set(this.member.id, this.member)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.user = new User(info.user ?? info.member!.user, this.client)
|
|
||||||
this.client.users.set(this.user.id, this.user)
|
|
||||||
|
|
||||||
if (info.data) {
|
|
||||||
this.name = info.data.name;
|
|
||||||
this.componentType = info.data.component_type
|
|
||||||
this.customId = info.data.custom_id
|
|
||||||
this.components = info.data.components
|
|
||||||
this.values = info.data.values
|
|
||||||
this.commandType = info.data.type
|
|
||||||
this.options = info.data.options
|
|
||||||
this.targetID = info.data.target_id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get data() {
|
|
||||||
return {
|
|
||||||
name: this.name,
|
|
||||||
component_type: this.componentType,
|
|
||||||
custom_id: this.customId,
|
|
||||||
components: this.components,
|
|
||||||
values: this.values,
|
|
||||||
type: this.commandType,
|
|
||||||
resolved: {
|
|
||||||
messages: this.messages.toRecord(),
|
|
||||||
users: this.users.toRecord(),
|
|
||||||
members: this.members.toRecord(),
|
|
||||||
roles: this.roles.toRecord(),
|
|
||||||
channels: this.channels.toRecord(),
|
|
||||||
attachments: this.attachments.toRecord(),
|
|
||||||
},
|
|
||||||
options: this.options,
|
|
||||||
target_id: this.targetID,
|
|
||||||
guild_id: this.guildID,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledges the interaction with a defer response
|
|
||||||
* Note: You can **not** use more than 1 initial interaction response per interaction.
|
|
||||||
*/
|
|
||||||
async acknowledge(flags?: number): Promise<void> {
|
|
||||||
return this.defer(flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Respond to the interaction with a followup message */
|
|
||||||
async createFollowup(content: string | InteractionContent, file?: FileContent | FileContent[]): Promise<Message> {
|
|
||||||
if (!this.acknowledged) {
|
|
||||||
throw new Error('createFollowup cannot be used to acknowledge an interaction, please use acknowledge, createMessage, or defer first.')
|
|
||||||
}
|
|
||||||
if (content !== undefined) {
|
|
||||||
if (typeof content !== 'object' || content === null) {
|
|
||||||
content = {
|
|
||||||
content: '' + content,
|
|
||||||
}
|
|
||||||
} else if (content.content !== undefined && typeof content.content !== 'string') {
|
|
||||||
content.content = '' + content.content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.executeWebhook.call(this.client, this.applicationID, this.token, {
|
|
||||||
...content,
|
|
||||||
wait: true,
|
|
||||||
file,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledges the interaction with a message. If already acknowledged runs createFollowup
|
|
||||||
* Note: You can **not** use more than 1 initial interaction response per interaction, use createFollowup if you have already responded with a different interaction response.
|
|
||||||
*/
|
|
||||||
async createMessage(content: string | InteractionContent, file?: FileContent | FileContent[]): Promise<void> {
|
|
||||||
if (this.acknowledged) {
|
|
||||||
// @ts-expect-error some eris magic at play here
|
|
||||||
return await this.createFollowup(content, file)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof content !== 'object' || content === null) {
|
|
||||||
content = {
|
|
||||||
content: '' + content,
|
|
||||||
}
|
|
||||||
} else if (content.content !== undefined && typeof content.content !== 'string') {
|
|
||||||
content.content = '' + content.content
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.client.createInteractionResponse
|
|
||||||
.call(
|
|
||||||
this.client,
|
|
||||||
this.id,
|
|
||||||
this.token,
|
|
||||||
{
|
|
||||||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
|
||||||
data: content,
|
|
||||||
},
|
|
||||||
file,
|
|
||||||
)
|
|
||||||
.then(() => this.update())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledges the interaction with a defer response
|
|
||||||
* Note: You can **not** use more than 1 initial interaction response per interaction.
|
|
||||||
*/
|
|
||||||
async defer(flags?: number): Promise<void> {
|
|
||||||
if (this.acknowledged) {
|
|
||||||
throw new Error('You have already acknowledged this interaction.')
|
|
||||||
}
|
|
||||||
return this.client.createInteractionResponse
|
|
||||||
.call(this.client, this.id, this.token, {
|
|
||||||
type: InteractionResponseTypes.DeferredChannelMessageWithSource,
|
|
||||||
data: {
|
|
||||||
flags: flags ?? 0,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then(() => this.update())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete a message */
|
|
||||||
async deleteMessage(messageID: BigString): Promise<void> {
|
|
||||||
if (!this.acknowledged) {
|
|
||||||
throw new Error('deleteMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, or defer first.')
|
|
||||||
}
|
|
||||||
return this.client.deleteWebhookMessage.call(this.client, this.applicationID, this.token, messageID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the Original message
|
|
||||||
* Warning: Will error with ephemeral messages.
|
|
||||||
*/
|
|
||||||
async deleteOriginalMessage(): Promise<void> {
|
|
||||||
if (!this.acknowledged) {
|
|
||||||
throw new Error('deleteOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, or defer first.')
|
|
||||||
}
|
|
||||||
return this.client.deleteWebhookMessage.call(this.client, this.applicationID, this.token, '@original')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit a message */
|
|
||||||
async editMessage(messageID: BigString, content: string | InteractionContentEdit, file?: FileContent | FileContent[]): Promise<Message> {
|
|
||||||
if (!this.acknowledged) {
|
|
||||||
throw new Error('editMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, or defer first.')
|
|
||||||
}
|
|
||||||
if (content !== undefined) {
|
|
||||||
if (typeof content !== 'object' || content === null) {
|
|
||||||
content = {
|
|
||||||
content: '' + content,
|
|
||||||
}
|
|
||||||
} else if (content.content !== undefined && typeof content.content !== 'string') {
|
|
||||||
content.content = '' + content.content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.editWebhookMessage.call(this.client, this.applicationID, this.token, messageID, {
|
|
||||||
...content,
|
|
||||||
file,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit the Original response message */
|
|
||||||
async editOriginalMessage(content: string | InteractionContentEdit, file?: FileContent | FileContent[]): Promise<Message> {
|
|
||||||
if (!this.acknowledged) {
|
|
||||||
throw new Error('editOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, or defer first.')
|
|
||||||
}
|
|
||||||
if (content !== undefined) {
|
|
||||||
if (typeof content !== 'object' || content === null) {
|
|
||||||
content = {
|
|
||||||
content: '' + content,
|
|
||||||
}
|
|
||||||
} else if (content.content !== undefined && typeof content.content !== 'string') {
|
|
||||||
content.content = '' + content.content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.client.editWebhookMessage.call(this.client, this.applicationID, this.token, '@original', {
|
|
||||||
...content,
|
|
||||||
file,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Original response message
|
|
||||||
* Warning: Will error with ephemeral messages.
|
|
||||||
*/
|
|
||||||
async getOriginalMessage(): Promise<Message> {
|
|
||||||
if (!this.acknowledged) {
|
|
||||||
throw new Error('getOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, or defer first.')
|
|
||||||
}
|
|
||||||
return this.client.getWebhookMessage.call(this.client, this.applicationID, this.token, '@original')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default CommandInteraction
|
|
||||||
@@ -1,296 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/restrict-plus-operands */
|
|
||||||
/* eslint-disable no-useless-call */
|
|
||||||
/* eslint-disable @typescript-eslint/return-await */
|
|
||||||
|
|
||||||
import type { BigString, DiscordInteraction, MessageComponentTypes } from '@discordeno/types'
|
|
||||||
import { InteractionResponseTypes } from '@discordeno/types'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
import type { AnyChannel, FileContent, InteractionApplicationCommandCallbackData, MessageWebhookContent, WebhookPayload } from '../../typings.js'
|
|
||||||
import type Guild from '../guilds/Guild.js'
|
|
||||||
import Member from '../guilds/Member.js'
|
|
||||||
import Message from '../Message.js'
|
|
||||||
import Permission from '../Permission.js'
|
|
||||||
import User from '../users/User.js'
|
|
||||||
import Interaction from './Interaction.js'
|
|
||||||
|
|
||||||
export class ComponentInteraction extends Interaction {
|
|
||||||
/** The channel id where this interaction occurred in. */
|
|
||||||
channelID: string
|
|
||||||
/** The guild id where this interaction occurred in. */
|
|
||||||
guildID?: string
|
|
||||||
/** The member object if this interaction occurred in a guild. */
|
|
||||||
member?: Member
|
|
||||||
/** The user object for the user that created this interaction. */
|
|
||||||
user: User
|
|
||||||
/** The permissions the app or bot has within the channel, the interaction was sent from. */
|
|
||||||
appPermissions?: Permission
|
|
||||||
/** The message object, if this interaction occurred on a message. */
|
|
||||||
message?: Message
|
|
||||||
/** The custom id of the component. */
|
|
||||||
customID: string
|
|
||||||
/** The type of component. */
|
|
||||||
componentType: MessageComponentTypes
|
|
||||||
/** The values from a selector component. */
|
|
||||||
values?: string[]
|
|
||||||
|
|
||||||
constructor(data: DiscordInteraction, client: Client) {
|
|
||||||
super(data, client)
|
|
||||||
|
|
||||||
this.channelID = data.channel_id!
|
|
||||||
// this.data = data.data;
|
|
||||||
this.guildID = data.guild_id
|
|
||||||
// Required to make a component
|
|
||||||
this.customID = data.data!.custom_id!
|
|
||||||
this.componentType = data.data!.component_type!
|
|
||||||
this.values = data.data!.values
|
|
||||||
|
|
||||||
if (data.member !== undefined && this.guild) {
|
|
||||||
this.member = new Member(data.member, this.guild, this.client)
|
|
||||||
this.guild.members.set(this.member.id, this.member)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.message !== undefined) {
|
|
||||||
this.message = new Message(data.message, this.client)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.user = new User(data.user ?? data.member!.user, this.client)
|
|
||||||
this.client.users.set(this.user.id, this.user)
|
|
||||||
|
|
||||||
if (data.app_permissions !== undefined) {
|
|
||||||
this.appPermissions = new Permission(data.app_permissions)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The channel if cached, where this interaction occurred. */
|
|
||||||
get channel(): AnyChannel | undefined {
|
|
||||||
return this.channelID ? this.client.getChannel(this.channelID) : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The guild if cached, where this interaction occurred. */
|
|
||||||
get guild(): Guild | undefined {
|
|
||||||
return this.guildID ? this.client.guilds.get(this.guildID) : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Acknowledges the interaction with a defer message update response */
|
|
||||||
async acknowledge(): Promise<void> {
|
|
||||||
return await this.deferUpdate()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Respond to the interaction with a followup message. */
|
|
||||||
async createFollowup(content: WebhookPayload, file?: FileContent | FileContent[]): Promise<Message> {
|
|
||||||
if (!this.acknowledged) {
|
|
||||||
throw new Error(
|
|
||||||
'createFollowup cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, or editParent first.',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (content !== undefined) {
|
|
||||||
if (typeof content !== 'object' || content === null) {
|
|
||||||
content = {
|
|
||||||
content: '' + content,
|
|
||||||
}
|
|
||||||
} else if (content.content !== undefined && typeof content.content !== 'string') {
|
|
||||||
content.content = '' + content.content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file) {
|
|
||||||
content.file = file
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.executeWebhook.call(this.client, this.applicationID, this.token, { ...content, wait: true })
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledges the interaction with a message. If already acknowledged runs createFollowup
|
|
||||||
* Note: You can **not** use more than 1 initial interaction response per interaction, use createFollowup if you have already responded with a different interaction response.
|
|
||||||
*/
|
|
||||||
async createMessage(content: InteractionApplicationCommandCallbackData, file?: FileContent | FileContent[]): Promise<Message | undefined> {
|
|
||||||
if (this.acknowledged) {
|
|
||||||
return await this.createFollowup(content, file)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (content !== undefined) {
|
|
||||||
if (typeof content !== 'object' || content === null) {
|
|
||||||
content = {
|
|
||||||
content: '' + content,
|
|
||||||
}
|
|
||||||
} else if (content.content !== undefined && typeof content.content !== 'string') {
|
|
||||||
content.content = '' + content.content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.client.createInteractionResponse
|
|
||||||
.call(
|
|
||||||
this.client,
|
|
||||||
this.id,
|
|
||||||
this.token,
|
|
||||||
{
|
|
||||||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
|
||||||
data: content,
|
|
||||||
},
|
|
||||||
file,
|
|
||||||
)
|
|
||||||
.then(() => this.update())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledges the interaction with a defer response
|
|
||||||
* Note: You can **not** use more than 1 initial interaction response per interaction.
|
|
||||||
*/
|
|
||||||
async defer(flags: number): Promise<void> {
|
|
||||||
if (this.acknowledged) {
|
|
||||||
throw new Error('You have already acknowledged this interaction.')
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.createInteractionResponse
|
|
||||||
.call(this.client, this.id, this.token, {
|
|
||||||
type: InteractionResponseTypes.DeferredChannelMessageWithSource,
|
|
||||||
data: {
|
|
||||||
flags: flags || 0,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then(() => this.update())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledges the interaction with a defer message update response
|
|
||||||
* Note: You can **not** use more than 1 initial interaction response per interaction.
|
|
||||||
*/
|
|
||||||
async deferUpdate(): Promise<void> {
|
|
||||||
if (this.acknowledged) {
|
|
||||||
throw new Error('You have already acknowledged this interaction.')
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.createInteractionResponse
|
|
||||||
.call(this.client, this.id, this.token, {
|
|
||||||
type: InteractionResponseTypes.DeferredUpdateMessage,
|
|
||||||
})
|
|
||||||
.then(() => this.update())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete a message */
|
|
||||||
async deleteMessage(messageID: BigString): Promise<void> {
|
|
||||||
if (!this.acknowledged) {
|
|
||||||
throw new Error(
|
|
||||||
'deleteMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, or editParent first.',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.deleteWebhookMessage.call(this.client, this.applicationID, this.token, messageID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the parent message
|
|
||||||
* Warning: Will error with ephemeral messages.
|
|
||||||
*/
|
|
||||||
async deleteOriginalMessage(): Promise<void> {
|
|
||||||
if (!this.acknowledged) {
|
|
||||||
throw new Error(
|
|
||||||
'deleteOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, or editParent first.',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.deleteWebhookMessage.call(this.client, this.applicationID, this.token, '@original')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit a message */
|
|
||||||
async editMessage(messageID: BigString, content: MessageWebhookContent, file?: FileContent | FileContent[]): Promise<Message> {
|
|
||||||
if (!this.acknowledged) {
|
|
||||||
throw new Error(
|
|
||||||
'editMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, or editParent first.',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (content !== undefined) {
|
|
||||||
if (typeof content !== 'object' || content === null) {
|
|
||||||
content = {
|
|
||||||
content: '' + content,
|
|
||||||
}
|
|
||||||
} else if (content.content !== undefined && typeof content.content !== 'string') {
|
|
||||||
content.content = '' + content.content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file) {
|
|
||||||
content.file = file
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.editWebhookMessage.call(this.client, this.applicationID, this.token, messageID, content)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Edit the parent message */
|
|
||||||
async editOriginalMessage(content: MessageWebhookContent, file?: FileContent | FileContent[]): Promise<Message> {
|
|
||||||
if (!this.acknowledged) {
|
|
||||||
throw new Error(
|
|
||||||
'editOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, or editParent first.',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (content !== undefined) {
|
|
||||||
if (typeof content !== 'object' || content === null) {
|
|
||||||
content = {
|
|
||||||
content: '' + content,
|
|
||||||
}
|
|
||||||
} else if (content.content !== undefined && typeof content.content !== 'string') {
|
|
||||||
content.content = '' + content.content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file) {
|
|
||||||
content.file = file
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.editWebhookMessage.call(this.client, this.applicationID, this.token, '@original', content)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledges the interaction by editing the parent message. If already acknowledged runs editOriginalMessage
|
|
||||||
* Note: You can **not** use more than 1 initial interaction response per interaction, use edit if you have already responded with a different interaction response.
|
|
||||||
* Warning: Will error with ephemeral messages.
|
|
||||||
*/
|
|
||||||
async editParent(content: InteractionApplicationCommandCallbackData, file?: FileContent | FileContent[]): Promise<Message | undefined> {
|
|
||||||
if (this.acknowledged) {
|
|
||||||
return this.editOriginalMessage(content)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (content !== undefined) {
|
|
||||||
if (typeof content !== 'object' || content === null) {
|
|
||||||
content = {
|
|
||||||
content: '' + content,
|
|
||||||
}
|
|
||||||
} else if (content.content !== undefined && typeof content.content !== 'string') {
|
|
||||||
content.content = '' + content.content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.client.createInteractionResponse
|
|
||||||
.call(
|
|
||||||
this.client,
|
|
||||||
this.id,
|
|
||||||
this.token,
|
|
||||||
{
|
|
||||||
type: InteractionResponseTypes.UpdateMessage,
|
|
||||||
data: content,
|
|
||||||
},
|
|
||||||
file,
|
|
||||||
)
|
|
||||||
.then(() => this.update())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the parent message
|
|
||||||
* Warning: Will error with ephemeral messages.
|
|
||||||
*/
|
|
||||||
async getOriginalMessage(): Promise<Message> {
|
|
||||||
if (!this.acknowledged) {
|
|
||||||
throw new Error(
|
|
||||||
'getOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, or editParent first.',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.client.getWebhookMessage.call(this.client, this.applicationID, this.token, '@original')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ComponentInteraction
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
import type { DiscordInteraction, InteractionTypes } from '@discordeno/types'
|
|
||||||
import Base from '../../Base.js'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
|
|
||||||
export class Interaction extends Base {
|
|
||||||
client: Client
|
|
||||||
applicationID: string
|
|
||||||
token: string
|
|
||||||
type: InteractionTypes
|
|
||||||
version: 1
|
|
||||||
acknowledged: boolean
|
|
||||||
|
|
||||||
constructor(data: DiscordInteraction, client: Client) {
|
|
||||||
super(data.id)
|
|
||||||
this.client = client
|
|
||||||
|
|
||||||
this.applicationID = data.application_id
|
|
||||||
this.token = data.token
|
|
||||||
this.type = data.type
|
|
||||||
this.version = data.version
|
|
||||||
this.acknowledged = false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use `.client`
|
|
||||||
*/
|
|
||||||
get _client(): Client {
|
|
||||||
return this.client
|
|
||||||
}
|
|
||||||
|
|
||||||
update() {
|
|
||||||
this.acknowledged = true
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use generateInteractionFrom(data, client) instead.
|
|
||||||
*/
|
|
||||||
static from(data: DiscordInteraction, client: Client) {
|
|
||||||
// Remove js hack of circular deps
|
|
||||||
console.error('Usage of Interaction.from() is deprecated. Use generateInteractionFrom(data, client) instead.')
|
|
||||||
client.emit('warn', new Error(`Usage of Interaction.from() is deprecated. Use generateInteractionFrom(data, client) instead.`))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Interaction
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
/* eslint-disable no-useless-call */
|
|
||||||
/* eslint-disable @typescript-eslint/return-await */
|
|
||||||
|
|
||||||
import { InteractionResponseTypes } from '@discordeno/types'
|
|
||||||
import Interaction from './Interaction.js'
|
|
||||||
|
|
||||||
export class PingInteraction extends Interaction {
|
|
||||||
/**
|
|
||||||
* Acknowledges the ping interaction with a pong response.
|
|
||||||
* Note: You can **not** use more than 1 initial interaction response per interaction.
|
|
||||||
*/
|
|
||||||
async acknowledge(): Promise<void> {
|
|
||||||
return this.pong()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledges the ping interaction with a pong response.
|
|
||||||
* Note: You can **not** use more than 1 initial interaction response per interaction.
|
|
||||||
*/
|
|
||||||
async pong(): Promise<void> {
|
|
||||||
if (this.acknowledged) {
|
|
||||||
throw new Error('You have already acknowledged this interaction.')
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.createInteractionResponse
|
|
||||||
.call(this.client, this.id, this.token, {
|
|
||||||
type: InteractionResponseTypes.Pong,
|
|
||||||
})
|
|
||||||
.then(() => this.update())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PingInteraction
|
|
||||||
@@ -1,493 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/restrict-plus-operands */
|
|
||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
/* eslint-disable no-useless-call */
|
|
||||||
|
|
||||||
import type { DiscordInteraction } from '@discordeno/types'
|
|
||||||
import { InteractionResponseTypes } from '@discordeno/types'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
import type {
|
|
||||||
ApplicationCommandOptionChoice,
|
|
||||||
FileContent,
|
|
||||||
InteractionContent,
|
|
||||||
InteractionContentEdit,
|
|
||||||
InteractionResponse,
|
|
||||||
PossiblyUncachedTextable,
|
|
||||||
TextableChannel,
|
|
||||||
} from '../../typings.js'
|
|
||||||
import Member from '../guilds/Member.js'
|
|
||||||
import Message from '../Message.js'
|
|
||||||
import Permission from '../Permission.js'
|
|
||||||
import User from '../users/User.js'
|
|
||||||
import Interaction from './Interaction.js'
|
|
||||||
|
|
||||||
export class UnknownInteraction<T extends PossiblyUncachedTextable = TextableChannel> extends Interaction {
|
|
||||||
channel?: T
|
|
||||||
data?: unknown
|
|
||||||
guildID?: string
|
|
||||||
member?: Member
|
|
||||||
message?: Message
|
|
||||||
type: number = 0
|
|
||||||
user?: User
|
|
||||||
appPermissions?: Permission
|
|
||||||
|
|
||||||
constructor(data: DiscordInteraction, client: Client) {
|
|
||||||
super(data, client)
|
|
||||||
|
|
||||||
if (data.channel_id !== undefined) {
|
|
||||||
this.channel = (this.client.getChannel(data.channel_id) as unknown as T) || {
|
|
||||||
id: data.channel_id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.data !== undefined) {
|
|
||||||
this.data = data.data
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.guild_id !== undefined) {
|
|
||||||
this.guildID = data.guild_id
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.member !== undefined) {
|
|
||||||
const guild = this.client.guilds.get(data.guild_id ?? '')!
|
|
||||||
this.member = new Member(data.member, guild, this.client)
|
|
||||||
guild.members.set(this.member.id, this.member)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.message !== undefined) {
|
|
||||||
this.message = new Message(data.message, this.client)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.user !== undefined) {
|
|
||||||
this.user = new User(data.user, this.client)
|
|
||||||
this.client.users.set(this.user.id, this.user)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.app_permissions !== undefined) {
|
|
||||||
this.appPermissions = new Permission(data.app_permissions)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledges the autocomplete interaction with a result of choices.
|
|
||||||
* Note: You can **not** use more than 1 initial interaction response per interaction.
|
|
||||||
* @arg {Object} data The data object
|
|
||||||
* @arg {Number} data.type The type of [interaction response](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-interaction-callback-type) to send
|
|
||||||
* @arg {Object} data.data The data to return to discord
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async acknowledge(data: InteractionResponse) {
|
|
||||||
if (this.acknowledged) {
|
|
||||||
throw new Error('You have already acknowledged this interaction.')
|
|
||||||
}
|
|
||||||
return await this.client.createInteractionResponse.call(this.client, this.id, this.token, data).then(() => this.update())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Respond to the interaction with a followup message
|
|
||||||
* @arg {String | Object} content A string or object. If an object is passed:
|
|
||||||
* @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default)
|
|
||||||
* @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here.
|
|
||||||
* @arg {Boolean | Array<String>} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow.
|
|
||||||
* @arg {Boolean | Array<String>} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow.
|
|
||||||
* @arg {Array<Object>} [content.components] An array of component objects
|
|
||||||
* @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only)
|
|
||||||
* @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only)
|
|
||||||
* @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2)
|
|
||||||
* @arg {String} [content.components[].label] The label to be displayed in the component (type 2)
|
|
||||||
* @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1)
|
|
||||||
* @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1)
|
|
||||||
* @arg {Array<Object>} [content.components[].options] The options for this component (type 3 only)
|
|
||||||
* @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected
|
|
||||||
* @arg {String} [content.components[].options[].description] The description for this option
|
|
||||||
* @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option
|
|
||||||
* @arg {String} content.components[].options[].label The label for this option
|
|
||||||
* @arg {Number | String} content.components[].options[].value The value for this option
|
|
||||||
* @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only)
|
|
||||||
* @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required
|
|
||||||
* @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu
|
|
||||||
* @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only)
|
|
||||||
* @arg {String} [content.content] A content string
|
|
||||||
* @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure
|
|
||||||
* @arg {Array<Object>} [options.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure
|
|
||||||
* @arg {Number} [content.flags] 64 for Ephemeral
|
|
||||||
* @arg {Boolean} [content.tts] Set the message TTS flag
|
|
||||||
* @arg {Object | Array<Object>} [file] A file object (or an Array of them)
|
|
||||||
* @arg {Buffer} file.file A buffer containing file data
|
|
||||||
* @arg {String} file.name What to name the file
|
|
||||||
* @returns {Promise<Message?>}
|
|
||||||
*/
|
|
||||||
async createFollowup(content: string | InteractionContent, file?: FileContent | FileContent[]) {
|
|
||||||
if (!this.acknowledged) {
|
|
||||||
throw new Error(
|
|
||||||
'createFollowup cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, editParent, pong, or result first.',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (content !== undefined) {
|
|
||||||
if (typeof content !== 'object' || content === null) {
|
|
||||||
content = {
|
|
||||||
content: '' + content,
|
|
||||||
}
|
|
||||||
} else if (content.content !== undefined && typeof content.content !== 'string') {
|
|
||||||
content.content = '' + content.content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (file) {
|
|
||||||
content.file = file
|
|
||||||
}
|
|
||||||
return await this.client.executeWebhook.call(this.client, this.applicationID, this.token, Object.assign({ wait: true as true }, content))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledges the interaction with a message. If already acknowledged runs createFollowup
|
|
||||||
* Note: You can **not** use more than 1 initial interaction response per interaction, use createFollowup if you have already responded with a different interaction response.
|
|
||||||
* @arg {String | Object} content A string or object. If an object is passed:
|
|
||||||
* @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default)
|
|
||||||
* @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here.
|
|
||||||
* @arg {Boolean | Array<String>} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow.
|
|
||||||
* @arg {Boolean | Array<String>} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow.
|
|
||||||
* @arg {Array<Object>} [content.components] An array of component objects
|
|
||||||
* @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only)
|
|
||||||
* @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only)
|
|
||||||
* @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2)
|
|
||||||
* @arg {String} [content.components[].label] The label to be displayed in the component (type 2)
|
|
||||||
* @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1)
|
|
||||||
* @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1)
|
|
||||||
* @arg {Array<Object>} [content.components[].options] The options for this component (type 3 only)
|
|
||||||
* @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected
|
|
||||||
* @arg {String} [content.components[].options[].description] The description for this option
|
|
||||||
* @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option
|
|
||||||
* @arg {String} content.components[].options[].label The label for this option
|
|
||||||
* @arg {Number | String} content.components[].options[].value The value for this option
|
|
||||||
* @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only)
|
|
||||||
* @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required
|
|
||||||
* @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu
|
|
||||||
* @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only)
|
|
||||||
* @arg {String} [content.content] A content string
|
|
||||||
* @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure
|
|
||||||
* @arg {Array<Object>} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure
|
|
||||||
* @arg {Boolean} [content.flags] 64 for Ephemeral
|
|
||||||
* @arg {Boolean} [content.tts] Set the message TTS flag
|
|
||||||
* @arg {Object | Array<Object>} [file] A file object (or an Array of them)
|
|
||||||
* @arg {Buffer} file.file A buffer containing file data
|
|
||||||
* @arg {String} file.name What to name the file
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async createMessage(content: string | InteractionContent, file?: FileContent | FileContent[]) {
|
|
||||||
if (this.acknowledged) {
|
|
||||||
return await this.createFollowup(content, file)
|
|
||||||
}
|
|
||||||
if (content !== undefined) {
|
|
||||||
if (typeof content !== 'object' || content === null) {
|
|
||||||
content = {
|
|
||||||
content: '' + content,
|
|
||||||
}
|
|
||||||
} else if (content.content !== undefined && typeof content.content !== 'string') {
|
|
||||||
content.content = '' + content.content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.createInteractionResponse
|
|
||||||
.call(
|
|
||||||
this.client,
|
|
||||||
this.id,
|
|
||||||
this.token,
|
|
||||||
{
|
|
||||||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
|
||||||
data: content,
|
|
||||||
},
|
|
||||||
file,
|
|
||||||
)
|
|
||||||
.then(() => this.update())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledges the interaction with a defer response
|
|
||||||
* Note: You can **not** use more than 1 initial interaction response per interaction.
|
|
||||||
* @arg {Number} [flags] 64 for Ephemeral
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async defer(flags: number) {
|
|
||||||
if (this.acknowledged) {
|
|
||||||
throw new Error('You have already acknowledged this interaction.')
|
|
||||||
}
|
|
||||||
return await this.client.createInteractionResponse
|
|
||||||
.call(this.client, this.id, this.token, {
|
|
||||||
type: InteractionResponseTypes.DeferredChannelMessageWithSource,
|
|
||||||
data: {
|
|
||||||
flags: flags || 0,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then(() => this.update())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledges the interaction with a defer message update response (Message Component only)
|
|
||||||
* Note: You can **not** use more than 1 initial interaction response per interaction.
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async deferUpdate() {
|
|
||||||
if (this.acknowledged) {
|
|
||||||
throw new Error('You have already acknowledged this interaction.')
|
|
||||||
}
|
|
||||||
return await this.client.createInteractionResponse
|
|
||||||
.call(this.client, this.id, this.token, {
|
|
||||||
type: InteractionResponseTypes.DeferredUpdateMessage,
|
|
||||||
})
|
|
||||||
.then(() => this.update())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a message
|
|
||||||
* @arg {String} messageID the id of the message to delete, or "@original" for the original response.
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async deleteMessage(messageID: string) {
|
|
||||||
if (!this.acknowledged) {
|
|
||||||
throw new Error(
|
|
||||||
'deleteMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, editParent, or pong first.',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return await this.client.deleteWebhookMessage.call(this.client, this.applicationID, this.token, messageID)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the Original message (or the parent message for components)
|
|
||||||
* Warning: Will error with ephemeral messages.
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async deleteOriginalMessage() {
|
|
||||||
if (!this.acknowledged) {
|
|
||||||
throw new Error(
|
|
||||||
'deleteOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, editParent, or pong first.',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return await this.client.deleteWebhookMessage.call(this.client, this.applicationID, this.token, '@original')
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Edit a message
|
|
||||||
* @arg {String} messageID the id of the message to edit, or "@original" for the original response.
|
|
||||||
* @arg {Object} content Interaction message edit options
|
|
||||||
* @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default)
|
|
||||||
* @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here.
|
|
||||||
* @arg {Boolean} [content.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to.
|
|
||||||
* @arg {Boolean | Array<String>} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow.
|
|
||||||
* @arg {Boolean | Array<String>} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow.
|
|
||||||
* @arg {Array<Object>} [content.components] An array of component objects
|
|
||||||
* @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only)
|
|
||||||
* @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only)
|
|
||||||
* @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2)
|
|
||||||
* @arg {String} [content.components[].label] The label to be displayed in the component (type 2)
|
|
||||||
* @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1)
|
|
||||||
* @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1)
|
|
||||||
* @arg {Array<Object>} [content.components[].options] The options for this component (type 3 only)
|
|
||||||
* @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected
|
|
||||||
* @arg {String} [content.components[].options[].description] The description for this option
|
|
||||||
* @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option
|
|
||||||
* @arg {String} content.components[].options[].label The label for this option
|
|
||||||
* @arg {Number | String} content.components[].options[].value The value for this option
|
|
||||||
* @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only)
|
|
||||||
* @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required
|
|
||||||
* @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu
|
|
||||||
* @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only)
|
|
||||||
* @arg {String} [content.content] A content string
|
|
||||||
* @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure
|
|
||||||
* @arg {Array<Object>} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure
|
|
||||||
* @arg {Object | Array<Object>} [file] A file object (or an Array of them)
|
|
||||||
* @arg {Buffer} file.file A buffer containing file data
|
|
||||||
* @arg {String} file.name What to name the file
|
|
||||||
* @returns {Promise<Message>}
|
|
||||||
*/
|
|
||||||
async editMessage(messageID: string, content: string | InteractionContentEdit, file?: FileContent | FileContent[]) {
|
|
||||||
if (!this.acknowledged) {
|
|
||||||
throw new Error(
|
|
||||||
'editMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, editParent, pong, or result first.',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (content !== undefined) {
|
|
||||||
if (typeof content !== 'object' || content === null) {
|
|
||||||
content = {
|
|
||||||
content: '' + content,
|
|
||||||
}
|
|
||||||
} else if (content.content !== undefined && typeof content.content !== 'string') {
|
|
||||||
content.content = '' + content.content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (file) {
|
|
||||||
content.file = file
|
|
||||||
}
|
|
||||||
return await this.client.editWebhookMessage.call(this.client, this.applicationID, this.token, messageID, content)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Edit the Original response message
|
|
||||||
* @arg {Object} content Interaction message edit options (or the parent message for components)
|
|
||||||
* @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default)
|
|
||||||
* @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here.
|
|
||||||
* @arg {Boolean} [content.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to.
|
|
||||||
* @arg {Boolean | Array<String>} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow.
|
|
||||||
* @arg {Boolean | Array<String>} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow.
|
|
||||||
* @arg {Array<Object>} [content.components] An array of component objects
|
|
||||||
* @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only)
|
|
||||||
* @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only)
|
|
||||||
* @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2)
|
|
||||||
* @arg {String} [content.components[].label] The label to be displayed in the component (type 2)
|
|
||||||
* @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1)
|
|
||||||
* @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1)
|
|
||||||
* @arg {Array<Object>} [content.components[].options] The options for this component (type 3 only)
|
|
||||||
* @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected
|
|
||||||
* @arg {String} [content.components[].options[].description] The description for this option
|
|
||||||
* @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option
|
|
||||||
* @arg {String} content.components[].options[].label The label for this option
|
|
||||||
* @arg {Number | String} content.components[].options[].value The value for this option
|
|
||||||
* @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only)
|
|
||||||
* @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required
|
|
||||||
* @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu
|
|
||||||
* @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only)
|
|
||||||
* @arg {String} [content.content] A content string
|
|
||||||
* @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure
|
|
||||||
* @arg {Array<Object>} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure
|
|
||||||
* @arg {Object | Array<Object>} [file] A file object (or an Array of them)
|
|
||||||
* @arg {Buffer} file.file A buffer containing file data
|
|
||||||
* @arg {String} file.name What to name the file
|
|
||||||
* @returns {Promise<Message>}
|
|
||||||
*/
|
|
||||||
async editOriginalMessage(content: string | InteractionContentEdit, file?: FileContent | FileContent[]) {
|
|
||||||
if (!this.acknowledged) {
|
|
||||||
throw new Error(
|
|
||||||
'editOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, editParent, pong, or result first.',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (content !== undefined) {
|
|
||||||
if (typeof content !== 'object' || content === null) {
|
|
||||||
content = {
|
|
||||||
content: '' + content,
|
|
||||||
}
|
|
||||||
} else if (content.content !== undefined && typeof content.content !== 'string') {
|
|
||||||
content.content = '' + content.content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (file) {
|
|
||||||
content.file = file
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.editWebhookMessage.call(this.client, this.applicationID, this.token, '@original', content)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledges the interaction by editing the parent message. If already acknowledged runs editOriginalMessage (Message Component only)
|
|
||||||
* Note: You can **not** use more than 1 initial interaction response per interaction, use edit if you have already responded with a different interaction response.
|
|
||||||
* Warning: Will error with ephemeral messages.
|
|
||||||
* @arg {String | Object} content What to edit the message with
|
|
||||||
* @arg {Object} [content.allowedMentions] A list of mentions to allow (overrides default)
|
|
||||||
* @arg {Boolean} [content.allowedMentions.everyone] Whether or not to allow @everyone/@here.
|
|
||||||
* @arg {Boolean} [content.allowedMentions.repliedUser] Whether or not to mention the author of the message being replied to.
|
|
||||||
* @arg {Boolean | Array<String>} [content.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow.
|
|
||||||
* @arg {Boolean | Array<String>} [content.allowedMentions.users] Whether or not to allow all user mentions, or an array of specific user mentions to allow.
|
|
||||||
* @arg {Array<Object>} [content.components] An array of component objects
|
|
||||||
* @arg {String} [content.components[].custom_id] The ID of the component (type 2 style 0-4 and type 3 only)
|
|
||||||
* @arg {Boolean} [content.components[].disabled] Whether the component is disabled (type 2 and 3 only)
|
|
||||||
* @arg {Object} [content.components[].emoji] The emoji to be displayed in the component (type 2)
|
|
||||||
* @arg {String} [content.components[].label] The label to be displayed in the component (type 2)
|
|
||||||
* @arg {Number} [content.components[].max_values] The maximum number of items that can be chosen (1-25, default 1)
|
|
||||||
* @arg {Number} [content.components[].min_values] The minimum number of items that must be chosen (0-25, default 1)
|
|
||||||
* @arg {Array<Object>} [content.components[].options] The options for this component (type 3 only)
|
|
||||||
* @arg {Boolean} [content.components[].options[].default] Whether this option should be the default value selected
|
|
||||||
* @arg {String} [content.components[].options[].description] The description for this option
|
|
||||||
* @arg {Object} [content.components[].options[].emoji] The emoji to be displayed in this option
|
|
||||||
* @arg {String} content.components[].options[].label The label for this option
|
|
||||||
* @arg {Number | String} content.components[].options[].value The value for this option
|
|
||||||
* @arg {String} [content.components[].placeholder] The placeholder text for the component when no option is selected (type 3 only)
|
|
||||||
* @arg {Number} [content.components[].style] The style of the component (type 2 only) - If 0-4, `custom_id` is required; if 5, `url` is required
|
|
||||||
* @arg {Number} content.components[].type The type of component - If 1, it is a collection and a `components` array (nested) is required; if 2, it is a button; if 3, it is a select menu
|
|
||||||
* @arg {String} [content.components[].url] The URL that the component should open for users (type 2 style 5 only)
|
|
||||||
* @arg {String} [content.content] A content string
|
|
||||||
* @arg {Object} [content.embed] An embed object. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure
|
|
||||||
* @arg {Array<Object>} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure
|
|
||||||
* @arg {Boolean} [content.flags] 64 for Ephemeral
|
|
||||||
* @arg {Boolean} [content.tts] Set the message TTS flag
|
|
||||||
* @arg {Object | Array<Object>} [file] A file object (or an Array of them)
|
|
||||||
* @arg {Buffer} file.file A buffer containing file data
|
|
||||||
* @arg {String} file.name What to name the file
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async editParent(content: InteractionContentEdit, file?: FileContent | FileContent[]) {
|
|
||||||
if (this.acknowledged) {
|
|
||||||
return await this.editOriginalMessage(content)
|
|
||||||
}
|
|
||||||
if (content !== undefined) {
|
|
||||||
if (typeof content !== 'object' || content === null) {
|
|
||||||
content = {
|
|
||||||
content: '' + content,
|
|
||||||
}
|
|
||||||
} else if (content.content !== undefined && typeof content.content !== 'string') {
|
|
||||||
content.content = '' + content.content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.client.createInteractionResponse
|
|
||||||
.call(
|
|
||||||
this.client,
|
|
||||||
this.id,
|
|
||||||
this.token,
|
|
||||||
{
|
|
||||||
type: InteractionResponseTypes.UpdateMessage,
|
|
||||||
data: content,
|
|
||||||
},
|
|
||||||
file,
|
|
||||||
)
|
|
||||||
.then(() => this.update())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Original response message (or the parent message for components)
|
|
||||||
* Warning: Will error with ephemeral messages.
|
|
||||||
* @returns {Promise<Message>}
|
|
||||||
*/
|
|
||||||
async getOriginalMessage() {
|
|
||||||
if (!this.acknowledged) {
|
|
||||||
throw new Error(
|
|
||||||
'getOriginalMessage cannot be used to acknowledge an interaction, please use acknowledge, createMessage, defer, deferUpdate, editParent, or pong first.',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return await this.client.getWebhookMessage.call(this.client, this.applicationID, this.token, '@original')
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledges the ping interaction with a pong response (Ping Only)
|
|
||||||
* Note: You can **not** use more than 1 initial interaction response per interaction.
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async pong() {
|
|
||||||
if (this.acknowledged) {
|
|
||||||
throw new Error('You have already acknowledged this interaction.')
|
|
||||||
}
|
|
||||||
return await this.client.createInteractionResponse
|
|
||||||
.call(this.client, this.id, this.token, {
|
|
||||||
type: InteractionResponseTypes.Pong,
|
|
||||||
})
|
|
||||||
.then(() => this.update())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledges the autocomplete interaction with a result of choices.
|
|
||||||
* Note: You can **not** use more than 1 initial interaction response per interaction.
|
|
||||||
* @arg {Array<Object>} choices The autocomplete choices to return to the user
|
|
||||||
* @arg {String | Number} choices[].name The choice display name
|
|
||||||
* @arg {String} choices[].value The choice value to return to the bot
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
async result(choices: ApplicationCommandOptionChoice[]) {
|
|
||||||
if (this.acknowledged) {
|
|
||||||
throw new Error('You have already acknowledged this interaction.')
|
|
||||||
}
|
|
||||||
return await this.client.createInteractionResponse
|
|
||||||
.call(this.client, this.id, this.token, {
|
|
||||||
type: InteractionResponseTypes.ApplicationCommandAutocompleteResult,
|
|
||||||
data: { choices },
|
|
||||||
})
|
|
||||||
.then(() => this.update())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default UnknownInteraction
|
|
||||||
@@ -1,304 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
import { GuildFeatures, type DiscordGuild } from '@discordeno/types'
|
|
||||||
import { ToggleBitfieldBigint } from './Toggle.js'
|
|
||||||
|
|
||||||
const featureNames = [
|
|
||||||
'inviteSplash',
|
|
||||||
'vipRegions',
|
|
||||||
'vanityUrl',
|
|
||||||
'verified',
|
|
||||||
'partnered',
|
|
||||||
'community',
|
|
||||||
'developerSupportServer',
|
|
||||||
'news',
|
|
||||||
'discoverable',
|
|
||||||
'featurable',
|
|
||||||
'animatedIcon',
|
|
||||||
'banner',
|
|
||||||
'welcomeScreenEnabled',
|
|
||||||
'memberVerificationGateEnabled',
|
|
||||||
'previewEnabled',
|
|
||||||
'ticketedEventsEnabled',
|
|
||||||
'monetizationEnabled',
|
|
||||||
'moreStickers',
|
|
||||||
'privateThreads',
|
|
||||||
'roleIcons',
|
|
||||||
'autoModeration',
|
|
||||||
'invitesDisabled',
|
|
||||||
'animatedBanner',
|
|
||||||
]
|
|
||||||
|
|
||||||
export const GuildToggle = {
|
|
||||||
/** Whether the bot is the owner of the guild */
|
|
||||||
owner: 1n << 0n,
|
|
||||||
/** Whether the server widget is enabled */
|
|
||||||
widgetEnabled: 1n << 1n,
|
|
||||||
/** Whether this is considered a large guild */
|
|
||||||
large: 1n << 2n,
|
|
||||||
/** Whether this guild is unavailable due to an outage */
|
|
||||||
unavailable: 1n << 3n,
|
|
||||||
/** Whether the guild has the boost progress bar enabled */
|
|
||||||
premiumProgressBarEnabled: 1n << 4n,
|
|
||||||
|
|
||||||
// GUILD FEATURES ARE BELOW THIS
|
|
||||||
|
|
||||||
/** Whether the guild has access to set an invite splash background */
|
|
||||||
inviteSplash: 1n << 5n,
|
|
||||||
/** Whether the guild has access to set 384 kbps bitrate in voice (previously VIP voice servers) */
|
|
||||||
vipRegions: 1n << 6n,
|
|
||||||
/** Whether the guild has access to set a vanity URL */
|
|
||||||
vanityUrl: 1n << 7n,
|
|
||||||
/** Whether the guild is verified */
|
|
||||||
verified: 1n << 8n,
|
|
||||||
/** Whether the guild is partnered */
|
|
||||||
partnered: 1n << 9n,
|
|
||||||
/** Whether the guild can enable welcome screen, Membership Screening, stage channels and discovery, and receives community updates */
|
|
||||||
community: 1n << 10n,
|
|
||||||
/** Whether the guild has access to set an animated guild banner image */
|
|
||||||
animatedBanner: 1n << 11n,
|
|
||||||
/** Whether the guild has access to create news channels */
|
|
||||||
news: 1n << 12n,
|
|
||||||
/** Whether the guild is able to be discovered in the directory */
|
|
||||||
discoverable: 1n << 13n,
|
|
||||||
/** Whether the guild is able to be featured in the directory */
|
|
||||||
featurable: 1n << 15n,
|
|
||||||
/** Whether the guild has access to set an animated guild icon */
|
|
||||||
animatedIcon: 1n << 16n,
|
|
||||||
/** Whether the guild has access to set a guild banner image */
|
|
||||||
banner: 1n << 17n,
|
|
||||||
/** Whether the guild has enabled the welcome screen */
|
|
||||||
welcomeScreenEnabled: 1n << 18n,
|
|
||||||
/** Whether the guild has enabled [Membership Screening](https://discord.com/developers/docs/resources/guild#membership-screening-object) */
|
|
||||||
memberVerificationGateEnabled: 1n << 19n,
|
|
||||||
/** Whether the guild can be previewed before joining via Membership Screening or the directory */
|
|
||||||
previewEnabled: 1n << 20n,
|
|
||||||
/** Whether the guild has enabled ticketed events */
|
|
||||||
ticketedEventsEnabled: 1n << 21n,
|
|
||||||
/** Whether the guild has enabled monetization */
|
|
||||||
monetizationEnabled: 1n << 22n,
|
|
||||||
/** Whether the guild has increased custom sticker slots */
|
|
||||||
moreStickers: 1n << 23n,
|
|
||||||
/** Whether the guild has access to create private threads */
|
|
||||||
privateThreads: 1n << 26n,
|
|
||||||
/** Whether the guild is able to set role icons */
|
|
||||||
roleIcons: 1n << 27n,
|
|
||||||
/** Whether the guild has set up auto moderation rules */
|
|
||||||
autoModeration: 1n << 28n,
|
|
||||||
/** Whether the guild has paused invites, preventing new users from joining */
|
|
||||||
invitesDisabled: 1n << 29n,
|
|
||||||
/** Whether the guild has been set as a support server on the App Directory */
|
|
||||||
developerSupportServer: 1n << 30n,
|
|
||||||
}
|
|
||||||
|
|
||||||
export class GuildToggles extends ToggleBitfieldBigint {
|
|
||||||
constructor(guildOrTogglesBigint: DiscordGuild | bigint) {
|
|
||||||
super()
|
|
||||||
|
|
||||||
if (typeof guildOrTogglesBigint === 'bigint') this.bitfield = guildOrTogglesBigint
|
|
||||||
else {
|
|
||||||
const guild = guildOrTogglesBigint
|
|
||||||
|
|
||||||
if (guild.owner) this.add(GuildToggle.owner)
|
|
||||||
if (guild.widget_enabled) this.add(GuildToggle.widgetEnabled)
|
|
||||||
if (guild.large) this.add(GuildToggle.large)
|
|
||||||
if (guild.unavailable) this.add(GuildToggle.unavailable)
|
|
||||||
if (guild.premium_progress_bar_enabled) this.add(GuildToggle.premiumProgressBarEnabled)
|
|
||||||
|
|
||||||
if (guild.features.includes(GuildFeatures.InviteSplash)) this.add(GuildToggle.inviteSplash)
|
|
||||||
if (guild.features.includes(GuildFeatures.VipRegions)) this.add(GuildToggle.vipRegions)
|
|
||||||
if (guild.features.includes(GuildFeatures.VanityUrl)) this.add(GuildToggle.vanityUrl)
|
|
||||||
if (guild.features.includes(GuildFeatures.Verified)) this.add(GuildToggle.verified)
|
|
||||||
if (guild.features.includes(GuildFeatures.Partnered)) this.add(GuildToggle.partnered)
|
|
||||||
if (guild.features.includes(GuildFeatures.Community)) this.add(GuildToggle.community)
|
|
||||||
if (guild.features.includes(GuildFeatures.DeveloperSupportServer)) this.add(GuildToggle.developerSupportServer)
|
|
||||||
if (guild.features.includes(GuildFeatures.AnimatedBanner)) this.add(GuildToggle.animatedBanner)
|
|
||||||
if (guild.features.includes(GuildFeatures.News)) this.add(GuildToggle.news)
|
|
||||||
if (guild.features.includes(GuildFeatures.Discoverable)) this.add(GuildToggle.discoverable)
|
|
||||||
if (guild.features.includes(GuildFeatures.Featurable)) this.add(GuildToggle.featurable)
|
|
||||||
if (guild.features.includes(GuildFeatures.AnimatedIcon)) this.add(GuildToggle.animatedIcon)
|
|
||||||
if (guild.features.includes(GuildFeatures.Banner)) this.add(GuildToggle.banner)
|
|
||||||
if (guild.features.includes(GuildFeatures.WelcomeScreenEnabled)) this.add(GuildToggle.welcomeScreenEnabled)
|
|
||||||
if (guild.features.includes(GuildFeatures.MemberVerificationGateEnabled)) {
|
|
||||||
this.add(GuildToggle.memberVerificationGateEnabled)
|
|
||||||
}
|
|
||||||
if (guild.features.includes(GuildFeatures.PreviewEnabled)) this.add(GuildToggle.previewEnabled)
|
|
||||||
if (guild.features.includes(GuildFeatures.TicketedEventsEnabled)) this.add(GuildToggle.ticketedEventsEnabled)
|
|
||||||
if (guild.features.includes(GuildFeatures.MoreStickers)) this.add(GuildToggle.moreStickers)
|
|
||||||
if (guild.features.includes(GuildFeatures.PrivateThreads)) this.add(GuildToggle.privateThreads)
|
|
||||||
if (guild.features.includes(GuildFeatures.RoleIcons)) this.add(GuildToggle.roleIcons)
|
|
||||||
if (guild.features.includes(GuildFeatures.AutoModeration)) this.add(GuildToggle.autoModeration)
|
|
||||||
if (guild.features.includes(GuildFeatures.InvitesDisabled)) this.add(GuildToggle.invitesDisabled)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get features() {
|
|
||||||
const features: GuildToggleKeys[] = []
|
|
||||||
for (const key of Object.keys(GuildToggle)) {
|
|
||||||
if (!featureNames.includes(key)) continue
|
|
||||||
if (!super.contains(GuildToggle[key as GuildToggleKeys])) continue
|
|
||||||
|
|
||||||
features.push(key as GuildToggleKeys)
|
|
||||||
}
|
|
||||||
|
|
||||||
return features
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the bot is the owner of the guild */
|
|
||||||
get owner() {
|
|
||||||
return this.has('owner')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the server widget is enabled */
|
|
||||||
get widgetEnabled() {
|
|
||||||
return this.has('widgetEnabled')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether this is considered a large guild */
|
|
||||||
get large() {
|
|
||||||
return this.has('large')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether this guild is unavailable due to an outage */
|
|
||||||
get unavailable() {
|
|
||||||
return this.has('unavailable')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild has the boost progress bar enabled */
|
|
||||||
get premiumProgressBarEnabled() {
|
|
||||||
return this.has('premiumProgressBarEnabled')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild has access to set an invite splash background */
|
|
||||||
get inviteSplash() {
|
|
||||||
return this.has('inviteSplash')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild has access to set 384 kbps bitrate in voice (previously VIP voice servers) */
|
|
||||||
get vipRegions() {
|
|
||||||
return this.has('vipRegions')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild has access to set a vanity URL */
|
|
||||||
get vanityUrl() {
|
|
||||||
return this.has('vanityUrl')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild is verified */
|
|
||||||
get verified() {
|
|
||||||
return this.has('verified')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild is partnered */
|
|
||||||
get partnered() {
|
|
||||||
return this.has('partnered')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild can enable welcome screen, Membership Screening, stage channels and discovery, and receives community updates */
|
|
||||||
get community() {
|
|
||||||
return this.has('community')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the Guild has been set as a support server on the App Directory */
|
|
||||||
get developerSupportServer() {
|
|
||||||
return this.has('developerSupportServer')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild has access to set an animated guild banner image */
|
|
||||||
get animatedBanner() {
|
|
||||||
return this.has('animatedBanner')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild has access to create news channels */
|
|
||||||
get news() {
|
|
||||||
return this.has('news')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild is able to be discovered in the directory */
|
|
||||||
get discoverable() {
|
|
||||||
return this.has('discoverable')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild is able to be featured in the directory */
|
|
||||||
get featurable() {
|
|
||||||
return this.has('featurable')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild has access to set an animated guild icon */
|
|
||||||
get animatedIcon() {
|
|
||||||
return this.has('animatedIcon')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild has access to set a guild banner image */
|
|
||||||
get banner() {
|
|
||||||
return this.has('banner')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild has enabled the welcome screen */
|
|
||||||
get welcomeScreenEnabled() {
|
|
||||||
return this.has('welcomeScreenEnabled')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild has enabled [Membership Screening](https://discord.com/developers/docs/resources/guild#membership-screening-object) */
|
|
||||||
get memberVerificationGateEnabled() {
|
|
||||||
return this.has('memberVerificationGateEnabled')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild can be previewed before joining via Membership Screening or the directory */
|
|
||||||
get previewEnabled() {
|
|
||||||
return this.has('previewEnabled')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild has enabled ticketed events */
|
|
||||||
get ticketedEventsEnabled() {
|
|
||||||
return this.has('ticketedEventsEnabled')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild has enabled monetization */
|
|
||||||
get monetizationEnabled() {
|
|
||||||
return this.has('monetizationEnabled')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild has increased custom sticker slots */
|
|
||||||
get moreStickers() {
|
|
||||||
return this.has('moreStickers')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild has access to create private threads */
|
|
||||||
get privateThreads() {
|
|
||||||
return this.has('privateThreads')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild is able to set role icons */
|
|
||||||
get roleIcons() {
|
|
||||||
return this.has('roleIcons')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild has set up auto moderation rules */
|
|
||||||
get autoModeration() {
|
|
||||||
return this.has('autoModeration')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether the guild has paused invites, preventing new users from joining */
|
|
||||||
get invitesDisabled() {
|
|
||||||
return this.has('invitesDisabled')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Checks whether or not the permissions exist in this */
|
|
||||||
has(permissions: GuildToggleKeys | GuildToggleKeys[]) {
|
|
||||||
if (!Array.isArray(permissions)) return super.contains(GuildToggle[permissions])
|
|
||||||
|
|
||||||
return super.contains(permissions.reduce((a, b) => (a |= GuildToggle[b]), 0n))
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Lists all the toggles for the role and whether or not each is true or false. */
|
|
||||||
list() {
|
|
||||||
const json: Record<string, boolean> = {}
|
|
||||||
for (const [key, value] of Object.entries(GuildToggle)) {
|
|
||||||
json[key] = super.contains(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return json as Record<GuildToggleKeys, boolean>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type GuildToggleKeys = keyof typeof GuildToggle
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
export class ToggleBitfield {
|
|
||||||
bitfield = 0
|
|
||||||
|
|
||||||
constructor(bitfield?: number) {
|
|
||||||
if (bitfield) this.bitfield = bitfield
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Tests whether or not this bitfield has the permission requested. */
|
|
||||||
contains(bits: number) {
|
|
||||||
return Boolean(this.bitfield & bits)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Adds some bits to the bitfield. */
|
|
||||||
add(bits: number) {
|
|
||||||
this.bitfield |= bits
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Removes some bits from the bitfield. */
|
|
||||||
remove(bits: number) {
|
|
||||||
this.bitfield &= ~bits
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ToggleBitfieldBigint {
|
|
||||||
bitfield = 0n
|
|
||||||
|
|
||||||
constructor(bitfield?: bigint) {
|
|
||||||
if (bitfield) this.bitfield = bitfield
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Tests whether or not this bitfield has the permission requested. */
|
|
||||||
contains(bits: bigint) {
|
|
||||||
return Boolean(this.bitfield & bits)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Adds some bits to the bitfield. */
|
|
||||||
add(bits: bigint) {
|
|
||||||
this.bitfield |= bits
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Removes some bits from the bitfield. */
|
|
||||||
remove(bits: bigint) {
|
|
||||||
this.bitfield &= ~bits
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
import type { DiscordVoiceState } from '@discordeno/types'
|
|
||||||
import { ToggleBitfield } from './Toggle.js'
|
|
||||||
|
|
||||||
export const VoiceStateToggle = {
|
|
||||||
/** Whether this user is deafened by the server */
|
|
||||||
deaf: 1 << 0,
|
|
||||||
/** Whether this user is muted by the server */
|
|
||||||
mute: 1 << 1,
|
|
||||||
/** Whether this user is locally deafened */
|
|
||||||
selfDeaf: 1 << 2,
|
|
||||||
/** Whether this user is locally muted */
|
|
||||||
selfMute: 1 << 3,
|
|
||||||
/** Whether this user is streaming using "Go Live" */
|
|
||||||
selfStream: 1 << 4,
|
|
||||||
/** Whether this user's camera is enabled */
|
|
||||||
selfVideo: 1 << 5,
|
|
||||||
/** Whether this user is muted by the current user */
|
|
||||||
suppress: 1 << 6,
|
|
||||||
}
|
|
||||||
|
|
||||||
export class VoiceStateToggles extends ToggleBitfield {
|
|
||||||
constructor(voiceOrTogglesInt: DiscordVoiceState | number) {
|
|
||||||
super()
|
|
||||||
|
|
||||||
if (typeof voiceOrTogglesInt === 'number') this.bitfield = voiceOrTogglesInt
|
|
||||||
else {
|
|
||||||
const voice = voiceOrTogglesInt
|
|
||||||
|
|
||||||
if (voice.deaf) this.add(VoiceStateToggle.deaf)
|
|
||||||
if (voice.mute) this.add(VoiceStateToggle.mute)
|
|
||||||
if (voice.self_deaf) this.add(VoiceStateToggle.selfDeaf)
|
|
||||||
if (voice.self_mute) this.add(VoiceStateToggle.selfMute)
|
|
||||||
if (voice.self_stream) this.add(VoiceStateToggle.selfStream)
|
|
||||||
if (voice.self_video) this.add(VoiceStateToggle.selfVideo)
|
|
||||||
if (voice.suppress) this.add(VoiceStateToggle.suppress)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether this user is deafened by the server */
|
|
||||||
get deaf() {
|
|
||||||
return this.has('deaf')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether this user is muted by the server */
|
|
||||||
get mute() {
|
|
||||||
return this.has('mute')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether this user is locally deafened */
|
|
||||||
get selfDeaf() {
|
|
||||||
return this.has('selfDeaf')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether this user is locally muted */
|
|
||||||
get selfMute() {
|
|
||||||
return this.has('selfMute')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether this user is streaming using "Go Live" */
|
|
||||||
get selfStream() {
|
|
||||||
return this.has('selfStream')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether this user's camera is enabled */
|
|
||||||
get selfVideo() {
|
|
||||||
return this.has('selfVideo')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether this user is muted by the current user */
|
|
||||||
get suppress() {
|
|
||||||
return this.has('suppress')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Checks whether or not the permissions exist in this */
|
|
||||||
has(permissions: VoiceStateToggleKeys | VoiceStateToggleKeys[]) {
|
|
||||||
if (!Array.isArray(permissions)) return super.contains(VoiceStateToggle[permissions])
|
|
||||||
|
|
||||||
return super.contains(permissions.reduce((a, b) => (a |= VoiceStateToggle[b]), 0))
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Lists all the toggles for the role and whether or not each is true or false. */
|
|
||||||
list() {
|
|
||||||
const json: Record<string, boolean> = {}
|
|
||||||
for (const [key, value] of Object.entries(VoiceStateToggle)) {
|
|
||||||
json[key] = super.contains(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return json as Record<VoiceStateToggleKeys, boolean>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type VoiceStateToggleKeys = keyof typeof VoiceStateToggle
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import type { PremiumTypes, DiscordUser } from '@discordeno/types'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
import User from './User.js'
|
|
||||||
|
|
||||||
export class ExtendedUser extends User {
|
|
||||||
email?: string | null
|
|
||||||
verified?: boolean
|
|
||||||
mfaEnabled?: boolean
|
|
||||||
premiumType?: PremiumTypes
|
|
||||||
|
|
||||||
constructor(data: DiscordUser, client: Client) {
|
|
||||||
super(data, client)
|
|
||||||
this.update(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
update(data: DiscordUser): void {
|
|
||||||
super.update(data)
|
|
||||||
if (data.email !== undefined) {
|
|
||||||
this.email = data.email
|
|
||||||
}
|
|
||||||
if (data.verified !== undefined) {
|
|
||||||
this.verified = data.verified
|
|
||||||
}
|
|
||||||
if (data.mfa_enabled !== undefined) {
|
|
||||||
this.mfaEnabled = data.mfa_enabled
|
|
||||||
}
|
|
||||||
if (data.premium_type !== undefined) {
|
|
||||||
this.premiumType = data.premium_type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON(['email', 'mfaEnabled', 'premium', 'verified', ...props])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ExtendedUser
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
/* eslint-disable no-useless-call */
|
|
||||||
import type { BigString, DiscordUser, UserFlags } from '@discordeno/types'
|
|
||||||
import Base from '../../Base.js'
|
|
||||||
import type Client from '../../Client.js'
|
|
||||||
import type { ImageFormat, ImageSize } from '../../Client.js'
|
|
||||||
import { BANNER, DEFAULT_USER_AVATAR, USER_AVATAR } from '../../Endpoints.js'
|
|
||||||
import type PrivateChannel from '../channels/Private.js'
|
|
||||||
|
|
||||||
export class User extends Base {
|
|
||||||
client: Client
|
|
||||||
bot: boolean
|
|
||||||
system: boolean
|
|
||||||
_avatar!: bigint | null
|
|
||||||
username!: string
|
|
||||||
discriminator!: string
|
|
||||||
publicFlags?: UserFlags
|
|
||||||
_banner!: bigint | null
|
|
||||||
accentColor?: number
|
|
||||||
|
|
||||||
constructor(data: DiscordUser, client: Client) {
|
|
||||||
super(data.id)
|
|
||||||
|
|
||||||
this.client = client
|
|
||||||
this.bot = !!data.bot
|
|
||||||
this.system = !!data.system
|
|
||||||
|
|
||||||
this.update(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated Use User.client Supported for Eris api compatibility. */
|
|
||||||
get _client(): Client {
|
|
||||||
return this.client
|
|
||||||
}
|
|
||||||
|
|
||||||
get avatar(): string | null {
|
|
||||||
if (!this._avatar) return null
|
|
||||||
|
|
||||||
return this.client.iconBigintToHash(this._avatar)
|
|
||||||
}
|
|
||||||
|
|
||||||
set avatar(value: BigString | null) {
|
|
||||||
this._avatar = typeof value === 'string' ? this.client.iconHashToBigInt(value) : value
|
|
||||||
}
|
|
||||||
|
|
||||||
get banner(): string | null {
|
|
||||||
if (!this._banner) return null
|
|
||||||
|
|
||||||
return this.client.iconBigintToHash(this._banner)
|
|
||||||
}
|
|
||||||
|
|
||||||
set banner(value: BigString | null) {
|
|
||||||
this._banner = typeof value === 'string' ? this.client.iconHashToBigInt(value) : value
|
|
||||||
}
|
|
||||||
|
|
||||||
get avatarURL(): string | null {
|
|
||||||
return this.avatar ? this.client._formatImage(USER_AVATAR(this.id, this.avatar)) : this.defaultAvatarURL
|
|
||||||
}
|
|
||||||
|
|
||||||
get bannerURL(): string | null {
|
|
||||||
if (!this.banner) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.client._formatImage(BANNER(this.id, this.banner))
|
|
||||||
}
|
|
||||||
|
|
||||||
get defaultAvatar(): string {
|
|
||||||
// @ts-expect-error some eris magic at play here
|
|
||||||
return (this.discriminator % 5).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
get defaultAvatarURL(): string {
|
|
||||||
return `${this.client.CDN_URL}${DEFAULT_USER_AVATAR(this.defaultAvatar)}.png`
|
|
||||||
}
|
|
||||||
|
|
||||||
get mention(): string {
|
|
||||||
return `<@${this.id}>`
|
|
||||||
}
|
|
||||||
|
|
||||||
get staticAvatarURL(): string {
|
|
||||||
return this.avatar ? this.client._formatImage(USER_AVATAR(this.id, this.avatar), 'jpg') : this.defaultAvatarURL
|
|
||||||
}
|
|
||||||
|
|
||||||
update(data: DiscordUser): void {
|
|
||||||
if (data.avatar !== undefined) {
|
|
||||||
this.avatar = data.avatar
|
|
||||||
}
|
|
||||||
if (data.username !== undefined) {
|
|
||||||
this.username = data.username
|
|
||||||
}
|
|
||||||
if (data.discriminator !== undefined) {
|
|
||||||
this.discriminator = data.discriminator
|
|
||||||
}
|
|
||||||
if (data.public_flags !== undefined) {
|
|
||||||
this.publicFlags = data.public_flags
|
|
||||||
}
|
|
||||||
if (data.banner !== undefined) {
|
|
||||||
this.banner = data.banner
|
|
||||||
}
|
|
||||||
if (data.accent_color !== undefined) {
|
|
||||||
this.accentColor = data.accent_color
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the user's avatar with the given format and size */
|
|
||||||
dynamicAvatarURL(format?: ImageFormat, size?: ImageSize): string {
|
|
||||||
return this.avatar ? this.client._formatImage(USER_AVATAR(this.id, this.avatar), format, size) : this.defaultAvatarURL
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the user's banner with the given format and size */
|
|
||||||
dynamicBannerURL(format?: ImageFormat, size?: ImageSize): string | null {
|
|
||||||
return this.banner ? this.client._formatImage(BANNER(this.id, this.banner), format, size) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a DM channel with the user, or create one if it does not exist
|
|
||||||
* @returns {Promise<PrivateChannel>}
|
|
||||||
*/
|
|
||||||
async getDMChannel(): Promise<PrivateChannel> {
|
|
||||||
return await this.client.getDMChannel.call(this.client, this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props: string[] = []): Record<string, any> {
|
|
||||||
return super.toJSON(['accentColor', 'avatar', 'banner', 'bot', 'discriminator', 'publicFlags', 'system', 'username', ...props])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default User
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,151 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
import Base from '../Base.js'
|
|
||||||
import type Client from '../Client.js'
|
|
||||||
import Collection from '../Collection.js'
|
|
||||||
import type { ShardManagerOptions } from '../typings.js'
|
|
||||||
import Shard from './Shard.js'
|
|
||||||
|
|
||||||
export class ShardManager extends Collection<number, Shard> {
|
|
||||||
/** The client manager */
|
|
||||||
client: Client
|
|
||||||
/** The options that were used to configure this manager. */
|
|
||||||
options: ShardManagerOptions
|
|
||||||
/** The buckets that this manager is handling. */
|
|
||||||
buckets: Map<number, number>
|
|
||||||
/** The queue in which to connect a shard. */
|
|
||||||
connectQueue: Shard[]
|
|
||||||
/** The timeout to use for connecting a shard. */
|
|
||||||
connectTimeout: NodeJS.Timeout | null
|
|
||||||
|
|
||||||
constructor(client: Client, options: ShardManagerOptions = {}) {
|
|
||||||
super()
|
|
||||||
this.client = client
|
|
||||||
|
|
||||||
this.options = Object.assign({ concurrency: 1 }, options)
|
|
||||||
this.buckets = new Map()
|
|
||||||
this.connectQueue = []
|
|
||||||
this.connectTimeout = null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use `.client` instead.
|
|
||||||
*/
|
|
||||||
get _client(): Client {
|
|
||||||
return this.client
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(shard: Shard) {
|
|
||||||
this.connectQueue.push(shard)
|
|
||||||
this.tryConnect()
|
|
||||||
}
|
|
||||||
|
|
||||||
get concurrency(): number {
|
|
||||||
return this.options.concurrency as number
|
|
||||||
}
|
|
||||||
|
|
||||||
setConcurrency(concurrency: number) {
|
|
||||||
this.options.concurrency = concurrency
|
|
||||||
}
|
|
||||||
|
|
||||||
spawn(id: number) {
|
|
||||||
let shard = this.get(id)
|
|
||||||
|
|
||||||
if (!shard) {
|
|
||||||
shard = new Shard(id, this.client)
|
|
||||||
this.set(id, shard)
|
|
||||||
|
|
||||||
shard
|
|
||||||
.on('ready', () => {
|
|
||||||
this.client.emit('shardReady', shard!.id)
|
|
||||||
if (this.client.ready) return
|
|
||||||
|
|
||||||
for (const other of this.values()) if (!other.ready) return
|
|
||||||
|
|
||||||
this.client.ready = true
|
|
||||||
this.client.startTime = Date.now()
|
|
||||||
|
|
||||||
this.client.emit('ready')
|
|
||||||
})
|
|
||||||
.on('resume', () => {
|
|
||||||
this.client.emit('shardResume', shard!.id)
|
|
||||||
if (this.client.ready) return
|
|
||||||
|
|
||||||
for (const other of this.values()) if (!other.ready) return
|
|
||||||
|
|
||||||
this.client.ready = true
|
|
||||||
this.client.startTime = Date.now()
|
|
||||||
this.client.emit('ready')
|
|
||||||
})
|
|
||||||
.on('disconnect', (error) => {
|
|
||||||
this.client.emit('shardDisconnect', error, shard!.id)
|
|
||||||
for (const other of this.values()) if (other.ready) return
|
|
||||||
|
|
||||||
this.client.ready = false
|
|
||||||
this.client.startTime = 0
|
|
||||||
this.client.emit('disconnect')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shard.status === 'disconnected') {
|
|
||||||
return this.connect(shard)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tryConnect() {
|
|
||||||
// nothing in queue
|
|
||||||
if (this.connectQueue.length === 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// loop over the connectQueue
|
|
||||||
for (const shard of this.connectQueue) {
|
|
||||||
// find the bucket for our shard
|
|
||||||
const rateLimitKey = shard.id % this.concurrency || 0
|
|
||||||
const lastConnect = this.buckets.get(rateLimitKey) ?? 0
|
|
||||||
|
|
||||||
// has enough time passed since the last connect for this bucket (5s/bucket)?
|
|
||||||
// alternatively if we have a sessionID, we can skip this check
|
|
||||||
if (!shard.sessionID && Date.now() - lastConnect < 5000) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Are there any connecting shards in the same bucket we should wait on?
|
|
||||||
if (this.some((s) => s.connecting && (s.id % this.concurrency || 0) === rateLimitKey)) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// connect the shard
|
|
||||||
shard.identify()
|
|
||||||
this.buckets.set(rateLimitKey, Date.now())
|
|
||||||
|
|
||||||
// remove the shard from the queue
|
|
||||||
const index = this.connectQueue.findIndex((s) => s.id === shard.id)
|
|
||||||
this.connectQueue.splice(index, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the next timeout if we have more shards to connect
|
|
||||||
if (!this.connectTimeout && this.connectQueue.length > 0) {
|
|
||||||
this.connectTimeout = setTimeout(() => {
|
|
||||||
this.connectTimeout = null
|
|
||||||
this.tryConnect()
|
|
||||||
}, 500)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_readyPacketCB(shardID: number) {
|
|
||||||
const rateLimitKey = shardID % this.concurrency || 0
|
|
||||||
this.buckets.set(rateLimitKey, Date.now())
|
|
||||||
|
|
||||||
this.tryConnect()
|
|
||||||
}
|
|
||||||
|
|
||||||
toString() {
|
|
||||||
return `[ShardManager ${this.size}]`
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(props = []) {
|
|
||||||
return Base.prototype.toJSON.call(this, ['buckets', 'connectQueue', 'connectTimeout', 'options', ...props])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ShardManager
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
import Base from './Base.js'
|
|
||||||
import type { ClientOptions } from './Client.js'
|
|
||||||
import Client from './Client.js'
|
|
||||||
import Collection from './Collection.js'
|
|
||||||
import * as Constants from './Constants.js'
|
|
||||||
import Shard from './gateway/Shard.js'
|
|
||||||
import RequestHandler from './RequestHandler.js'
|
|
||||||
import { CategoryChannel } from './Structures/channels/Category.js'
|
|
||||||
import Channel from './Structures/channels/Channel.js'
|
|
||||||
import Guild, { GuildChannel } from './Structures/channels/Guild.js'
|
|
||||||
import { NewsChannel } from './Structures/channels/News.js'
|
|
||||||
import { PrivateChannel } from './Structures/channels/Private.js'
|
|
||||||
import { StageChannel } from './Structures/channels/Stage.js'
|
|
||||||
import { TextChannel } from './Structures/channels/Text.js'
|
|
||||||
import { TextVoiceChannel } from './Structures/channels/TextVoice.js'
|
|
||||||
import Member, { ThreadMember } from './Structures/channels/threads/Member.js'
|
|
||||||
import { NewsThreadChannel } from './Structures/channels/threads/NewsThread.js'
|
|
||||||
import { PrivateThreadChannel } from './Structures/channels/threads/PrivateThread.js'
|
|
||||||
import { PublicThreadChannel } from './Structures/channels/threads/PublicThread.js'
|
|
||||||
import { ThreadChannel } from './Structures/channels/threads/Thread.js'
|
|
||||||
import { VoiceChannel } from './Structures/channels/Voice.js'
|
|
||||||
import { GuildIntegration } from './Structures/guilds/Integration.js'
|
|
||||||
import { GuildPreview } from './Structures/guilds/Preview.js'
|
|
||||||
import Role from './Structures/guilds/Role.js'
|
|
||||||
import StageInstance from './Structures/guilds/StageInstance.js'
|
|
||||||
import { GuildTemplate } from './Structures/guilds/Template.js'
|
|
||||||
import { UnavailableGuild } from './Structures/guilds/Unavailable.js'
|
|
||||||
import { VoiceState } from './Structures/guilds/VoiceState.js'
|
|
||||||
import { AutocompleteInteraction } from './Structures/interactions/Autocomplete.js'
|
|
||||||
import Command, { CommandInteraction } from './Structures/interactions/Command.js'
|
|
||||||
import { ComponentInteraction } from './Structures/interactions/Component.js'
|
|
||||||
import Interaction from './Structures/interactions/Interaction.js'
|
|
||||||
import { PingInteraction } from './Structures/interactions/Ping.js'
|
|
||||||
import { UnknownInteraction } from './Structures/interactions/Unknown.js'
|
|
||||||
import Invite from './Structures/Invite.js'
|
|
||||||
import Message from './Structures/Message.js'
|
|
||||||
import Permission from './Structures/Permission.js'
|
|
||||||
import PermissionOverwrite from './Structures/PermissionOverwrite.js'
|
|
||||||
import { ExtendedUser } from './Structures/users/Extended.js'
|
|
||||||
import User from './Structures/users/User.js'
|
|
||||||
import Bucket from './utils/Bucket.js'
|
|
||||||
import DiscordRESTError from './utils/DiscordRESTError.js'
|
|
||||||
// TODO: MAKE THIS DYNAMIC FROM PACKAGE.JSON
|
|
||||||
export const VERSION = "19.0.0";
|
|
||||||
|
|
||||||
export function DiscordenoClient(token: string, options: ClientOptions): Client {
|
|
||||||
return new Client(token, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
DiscordenoClient.AutocompleteInteraction = AutocompleteInteraction
|
|
||||||
DiscordenoClient.Base = Base
|
|
||||||
DiscordenoClient.Bucket = Bucket
|
|
||||||
DiscordenoClient.CategoryChannel = CategoryChannel
|
|
||||||
DiscordenoClient.Channel = Channel
|
|
||||||
DiscordenoClient.CommandInteraction = CommandInteraction
|
|
||||||
DiscordenoClient.ComponentInteraction = ComponentInteraction
|
|
||||||
DiscordenoClient.Client = Client
|
|
||||||
DiscordenoClient.Collection = Collection
|
|
||||||
DiscordenoClient.Command = Command
|
|
||||||
// DiscordenoClient.CommandClient = CommandClient
|
|
||||||
DiscordenoClient.Constants = Constants
|
|
||||||
// DiscordenoClient.DiscordHTTPError = DiscordHTTPError
|
|
||||||
DiscordenoClient.DiscordRESTError = DiscordRESTError
|
|
||||||
DiscordenoClient.ExtendedUser = ExtendedUser
|
|
||||||
DiscordenoClient.Guild = Guild
|
|
||||||
DiscordenoClient.GuildChannel = GuildChannel
|
|
||||||
DiscordenoClient.GuildIntegration = GuildIntegration
|
|
||||||
DiscordenoClient.GuildPreview = GuildPreview
|
|
||||||
DiscordenoClient.GuildTemplate = GuildTemplate
|
|
||||||
DiscordenoClient.Interaction = Interaction
|
|
||||||
DiscordenoClient.Invite = Invite
|
|
||||||
DiscordenoClient.Member = Member
|
|
||||||
DiscordenoClient.Message = Message
|
|
||||||
DiscordenoClient.NewsChannel = NewsChannel
|
|
||||||
DiscordenoClient.NewsThreadChannel = NewsThreadChannel
|
|
||||||
DiscordenoClient.Permission = Permission
|
|
||||||
DiscordenoClient.PermissionOverwrite = PermissionOverwrite
|
|
||||||
DiscordenoClient.PingInteraction = PingInteraction
|
|
||||||
DiscordenoClient.PrivateChannel = PrivateChannel
|
|
||||||
DiscordenoClient.PrivateThreadChannel = PrivateThreadChannel
|
|
||||||
DiscordenoClient.PublicThreadChannel = PublicThreadChannel
|
|
||||||
DiscordenoClient.RequestHandler = RequestHandler
|
|
||||||
DiscordenoClient.Role = Role
|
|
||||||
DiscordenoClient.Shard = Shard
|
|
||||||
DiscordenoClient.StageChannel = StageChannel
|
|
||||||
DiscordenoClient.StageInstance = StageInstance
|
|
||||||
DiscordenoClient.TextChannel = TextChannel
|
|
||||||
DiscordenoClient.TextVoiceChannel = TextVoiceChannel
|
|
||||||
DiscordenoClient.ThreadChannel = ThreadChannel
|
|
||||||
DiscordenoClient.ThreadMember = ThreadMember
|
|
||||||
DiscordenoClient.UnavailableGuild = UnavailableGuild
|
|
||||||
DiscordenoClient.UnknownInteraction = UnknownInteraction
|
|
||||||
DiscordenoClient.User = User
|
|
||||||
DiscordenoClient.VERSION = VERSION
|
|
||||||
DiscordenoClient.VoiceChannel = VoiceChannel
|
|
||||||
DiscordenoClient.VoiceState = VoiceState
|
|
||||||
|
|
||||||
export * from './Base.js'
|
|
||||||
export * from './Client.js'
|
|
||||||
export * from './Collection.js'
|
|
||||||
export * from './Constants.js'
|
|
||||||
export * from './Endpoints.js'
|
|
||||||
export * from './gateway/Shard.js'
|
|
||||||
export * from './gateway/ShardManager.js'
|
|
||||||
export * from './Structures/channels/Category.js'
|
|
||||||
export * from './Structures/channels/Channel.js'
|
|
||||||
export * from './Structures/channels/Guild.js'
|
|
||||||
export * from './Structures/channels/News.js'
|
|
||||||
export * from './Structures/channels/Private.js'
|
|
||||||
export * from './Structures/channels/Stage.js'
|
|
||||||
export * from './Structures/channels/Text.js'
|
|
||||||
export * from './Structures/channels/TextVoice.js'
|
|
||||||
export * from './Structures/channels/threads/Member.js'
|
|
||||||
export * from './Structures/channels/threads/NewsThread.js'
|
|
||||||
export * from './Structures/channels/threads/PrivateThread.js'
|
|
||||||
export * from './Structures/channels/threads/PublicThread.js'
|
|
||||||
export * from './Structures/channels/threads/Thread.js'
|
|
||||||
export * from './Structures/channels/Voice.js'
|
|
||||||
export * from './Structures/guilds/AuditLogEntry.js'
|
|
||||||
export * from './Structures/guilds/Guild.js'
|
|
||||||
export * from './Structures/guilds/Integration.js'
|
|
||||||
export * from './Structures/guilds/Member.js'
|
|
||||||
export * from './Structures/guilds/Preview.js'
|
|
||||||
export * from './Structures/guilds/Role.js'
|
|
||||||
export * from './Structures/guilds/StageInstance.js'
|
|
||||||
export * from './Structures/guilds/Template.js'
|
|
||||||
export * from './Structures/guilds/Unavailable.js'
|
|
||||||
export * from './Structures/guilds/VoiceState.js'
|
|
||||||
export * from './Structures/interactions/Autocomplete.js'
|
|
||||||
export * from './Structures/interactions/Command.js'
|
|
||||||
export * from './Structures/interactions/Component.js'
|
|
||||||
export * from './Structures/interactions/Interaction.js'
|
|
||||||
export * from './Structures/interactions/Ping.js'
|
|
||||||
export * from './Structures/interactions/Unknown.js'
|
|
||||||
export * from './Structures/Invite.js'
|
|
||||||
export * from './Structures/Message.js'
|
|
||||||
export * from './Structures/Permission.js'
|
|
||||||
export * from './Structures/PermissionOverwrite.js'
|
|
||||||
export * from './Structures/users/Extended.js'
|
|
||||||
export * from './Structures/users/User.js'
|
|
||||||
export * from './typings.js'
|
|
||||||
export * from './utils/BrowserWebSocket.js'
|
|
||||||
export * from './utils/Bucket.js'
|
|
||||||
export * from './utils/DiscordRESTError.js'
|
|
||||||
export * from './utils/generate.js'
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,105 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/class-literal-property-style */
|
|
||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
import { EventEmitter } from 'node:events'
|
|
||||||
|
|
||||||
class BrowserWebSocketError extends Error {
|
|
||||||
static CONNECTING: 0 = 0
|
|
||||||
static OPEN: 1
|
|
||||||
static CLOSING: 2
|
|
||||||
static CLOSED: 3
|
|
||||||
|
|
||||||
readyState: number = 0
|
|
||||||
event: Event
|
|
||||||
|
|
||||||
constructor(message: string | undefined, event: Event) {
|
|
||||||
super(message)
|
|
||||||
|
|
||||||
this.event = event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a browser's websocket usable by Eris
|
|
||||||
* @extends EventEmitter
|
|
||||||
* @prop {String} url The URL to connect to
|
|
||||||
*/
|
|
||||||
class BrowserWebSocket extends EventEmitter {
|
|
||||||
_ws: WebSocket
|
|
||||||
|
|
||||||
constructor(url: string) {
|
|
||||||
super()
|
|
||||||
|
|
||||||
if (typeof window === 'undefined') {
|
|
||||||
throw new Error('BrowserWebSocket cannot be used outside of a browser environment')
|
|
||||||
}
|
|
||||||
|
|
||||||
this._ws = new window.WebSocket(url)
|
|
||||||
this._ws.onopen = () => this.emit('open')
|
|
||||||
this._ws.onmessage = this._onMessage.bind(this)
|
|
||||||
this._ws.onerror = (event) => this.emit('error', new BrowserWebSocketError('Unknown error', event))
|
|
||||||
this._ws.onclose = (event) => this.emit('close', event.code, event.reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
get readyState() {
|
|
||||||
return this._ws.readyState
|
|
||||||
}
|
|
||||||
|
|
||||||
static get CONNECTING() {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
static set CONNECTING(state: number) {
|
|
||||||
BrowserWebSocket.CONNECTING = state
|
|
||||||
}
|
|
||||||
|
|
||||||
static get OPEN() {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
static set OPEN(state: number) {
|
|
||||||
BrowserWebSocket.OPEN = state
|
|
||||||
}
|
|
||||||
|
|
||||||
static get CLOSING() {
|
|
||||||
return 2
|
|
||||||
}
|
|
||||||
|
|
||||||
static set CLOSING(state: number) {
|
|
||||||
BrowserWebSocket.CLOSING = state
|
|
||||||
}
|
|
||||||
|
|
||||||
static get CLOSED() {
|
|
||||||
return 3
|
|
||||||
}
|
|
||||||
|
|
||||||
static set CLOSED(state: number) {
|
|
||||||
BrowserWebSocket.CLOSED = state
|
|
||||||
}
|
|
||||||
|
|
||||||
close(code?: number, reason?: string) {
|
|
||||||
return this._ws.close(code, reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
removeEventListener(type: string | symbol, listener: (...args: any[]) => void): this {
|
|
||||||
return this.removeListener(type, listener)
|
|
||||||
}
|
|
||||||
|
|
||||||
send(data: string | ArrayBufferLike | Blob | ArrayBufferView) {
|
|
||||||
return this._ws.send(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
terminate() {
|
|
||||||
return this._ws.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
async _onMessage(event: MessageEvent<any>) {
|
|
||||||
if (event.data instanceof window.Blob) {
|
|
||||||
this.emit('message', await event.data.arrayBuffer())
|
|
||||||
} else {
|
|
||||||
this.emit('message', event.data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default BrowserWebSocket
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
interface BucketOptions {
|
|
||||||
latencyRef?: { latency: number }
|
|
||||||
reservedTokens?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle ratelimiting something
|
|
||||||
* @prop {Number} interval How long (in ms) to wait between clearing used tokens
|
|
||||||
* @prop {Number} lastReset Timestamp of last token clearing
|
|
||||||
* @prop {Number} lastSend Timestamp of last token consumption
|
|
||||||
* @prop {Number} tokenLimit The max number tokens the bucket can consume per interval
|
|
||||||
* @prop {Number} tokens How many tokens the bucket has consumed in this interval
|
|
||||||
*/
|
|
||||||
class Bucket {
|
|
||||||
interval: number
|
|
||||||
latencyRef: { latency: number }
|
|
||||||
lastReset: number
|
|
||||||
lastSend: number
|
|
||||||
tokenLimit: number
|
|
||||||
tokens: number
|
|
||||||
reservedTokens: number
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
||||||
_queue: Array<{ func: Function; priority: boolean }>
|
|
||||||
timeout: NodeJS.Timeout | null = null
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a Bucket
|
|
||||||
* @arg {Number} tokenLimit The max number of tokens the bucket can consume per interval
|
|
||||||
* @arg {Number} interval How long (in ms) to wait between clearing used tokens
|
|
||||||
* @arg {Object} [options] Optional parameters
|
|
||||||
* @arg {Object} options.latencyRef A latency reference object
|
|
||||||
* @arg {Number} options.latencyRef.latency Interval between consuming tokens
|
|
||||||
* @arg {Number} options.reservedTokens How many tokens to reserve for priority operations
|
|
||||||
*/
|
|
||||||
constructor(tokenLimit: number, interval: number, options: BucketOptions = {} as BucketOptions) {
|
|
||||||
this.tokenLimit = tokenLimit
|
|
||||||
this.interval = interval
|
|
||||||
this.latencyRef = options.latencyRef ?? { latency: 0 }
|
|
||||||
this.lastReset = this.tokens = this.lastSend = 0
|
|
||||||
this.reservedTokens = options.reservedTokens ?? 0
|
|
||||||
this._queue = []
|
|
||||||
}
|
|
||||||
|
|
||||||
check() {
|
|
||||||
if (this.timeout ?? this._queue.length === 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (this.lastReset + this.interval + this.tokenLimit * this.latencyRef.latency < Date.now()) {
|
|
||||||
this.lastReset = Date.now()
|
|
||||||
this.tokens = Math.max(0, this.tokens - this.tokenLimit)
|
|
||||||
}
|
|
||||||
|
|
||||||
let val
|
|
||||||
let tokensAvailable = this.tokens < this.tokenLimit
|
|
||||||
let unreservedTokensAvailable = this.tokens < this.tokenLimit - this.reservedTokens
|
|
||||||
while (this._queue.length > 0 && (unreservedTokensAvailable || (tokensAvailable && this._queue[0].priority))) {
|
|
||||||
this.tokens++
|
|
||||||
tokensAvailable = this.tokens < this.tokenLimit
|
|
||||||
unreservedTokensAvailable = this.tokens < this.tokenLimit - this.reservedTokens
|
|
||||||
const item = this._queue.shift()
|
|
||||||
val = this.latencyRef.latency - Date.now() + this.lastSend
|
|
||||||
if (this.latencyRef.latency === 0 || val <= 0) {
|
|
||||||
item!.func()
|
|
||||||
this.lastSend = Date.now()
|
|
||||||
} else {
|
|
||||||
setTimeout(() => {
|
|
||||||
item!.func()
|
|
||||||
}, val)
|
|
||||||
this.lastSend = Date.now() + val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._queue.length > 0 && !this.timeout) {
|
|
||||||
this.timeout = setTimeout(
|
|
||||||
() => {
|
|
||||||
this.timeout = null
|
|
||||||
this.check()
|
|
||||||
},
|
|
||||||
this.tokens < this.tokenLimit
|
|
||||||
? this.latencyRef.latency
|
|
||||||
: Math.max(0, this.lastReset + this.interval + this.tokenLimit * this.latencyRef.latency - Date.now()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queue something in the Bucket
|
|
||||||
* @arg {Function} func A callback to call when a token can be consumed
|
|
||||||
* @arg {Boolean} [priority=false] Whether or not the callback should use reserved tokens
|
|
||||||
*/
|
|
||||||
queue(func: () => void, priority = false) {
|
|
||||||
if (priority) {
|
|
||||||
this._queue.unshift({ func, priority })
|
|
||||||
} else {
|
|
||||||
this._queue.push({ func, priority })
|
|
||||||
}
|
|
||||||
this.check()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Bucket
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
import type { ClientRequest, IncomingHttpHeaders, IncomingMessage } from 'http'
|
|
||||||
import type { HTTPResponse } from '../typings.js'
|
|
||||||
|
|
||||||
export class DiscordRESTError extends Error {
|
|
||||||
code: number = -1
|
|
||||||
req!: ClientRequest
|
|
||||||
res!: IncomingMessage
|
|
||||||
response!: HTTPResponse
|
|
||||||
|
|
||||||
constructor(req: ClientRequest, res: IncomingMessage, response: HTTPResponse, stack: string) {
|
|
||||||
super()
|
|
||||||
|
|
||||||
Object.defineProperty(this, 'req', {
|
|
||||||
enumerable: false,
|
|
||||||
value: req,
|
|
||||||
})
|
|
||||||
Object.defineProperty(this, 'res', {
|
|
||||||
enumerable: false,
|
|
||||||
value: res,
|
|
||||||
})
|
|
||||||
Object.defineProperty(this, 'response', {
|
|
||||||
enumerable: false,
|
|
||||||
value: response,
|
|
||||||
})
|
|
||||||
|
|
||||||
Object.defineProperty(this, 'code', {
|
|
||||||
enumerable: false,
|
|
||||||
value: +response.code || -1,
|
|
||||||
})
|
|
||||||
let message = response.message || 'Unknown error'
|
|
||||||
if (response.errors) {
|
|
||||||
message += '\n ' + this.flattenErrors(response.errors).join('\n ')
|
|
||||||
} else {
|
|
||||||
const errors = this.flattenErrors(response)
|
|
||||||
if (errors.length > 0) {
|
|
||||||
message += '\n ' + errors.join('\n ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Object.defineProperty(this, 'message', {
|
|
||||||
enumerable: false,
|
|
||||||
value: message,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (stack) {
|
|
||||||
this.stack = this.name + ': ' + this.message + '\n' + stack
|
|
||||||
} else {
|
|
||||||
Error.captureStackTrace(this, DiscordRESTError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get headers(): IncomingHttpHeaders {
|
|
||||||
return this.response.headers
|
|
||||||
}
|
|
||||||
|
|
||||||
get name(): string {
|
|
||||||
return `${this.constructor.name} [${this.code}]`
|
|
||||||
}
|
|
||||||
|
|
||||||
flattenErrors(errors: HTTPResponse, keyPrefix?: string): string[] {
|
|
||||||
let messages: string[] = []
|
|
||||||
for (const fieldName of Object.keys(errors)) {
|
|
||||||
if (fieldName === 'message' || fieldName === 'code') {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
const prefix = `${keyPrefix ?? ""}${fieldName}`;
|
|
||||||
|
|
||||||
// @ts-expect-error js hack from eris
|
|
||||||
if (errors[fieldName]._errors) {
|
|
||||||
// @ts-expect-error js hack from eris
|
|
||||||
messages = messages.concat(errors[fieldName]._errors.map((obj: any) => `${prefix}: ${obj.message as string}`))
|
|
||||||
// @ts-expect-error js hack from eris
|
|
||||||
} else if (Array.isArray(errors[fieldName])) {
|
|
||||||
// @ts-expect-error js hack from eris
|
|
||||||
messages = messages.concat(errors[fieldName].map((str: string) => `${prefix}: ${str}`))
|
|
||||||
// @ts-expect-error js hack from eris
|
|
||||||
} else if (typeof errors[fieldName] === 'object') {
|
|
||||||
// @ts-expect-error js hack from eris
|
|
||||||
messages = messages.concat(this.flattenErrors(errors[fieldName], `${prefix}.`))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return messages
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DiscordRESTError
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
import type { DiscordChannel, DiscordInteraction } from '@discordeno/types'
|
|
||||||
import { ChannelTypes, InteractionTypes } from '@discordeno/types'
|
|
||||||
import type Client from '../Client.js'
|
|
||||||
import type { TextableChannel } from '../index.js'
|
|
||||||
import CategoryChannel from '../Structures/channels/Category.js'
|
|
||||||
import Channel from '../Structures/channels/Channel.js'
|
|
||||||
import GuildChannel from '../Structures/channels/Guild.js'
|
|
||||||
import NewsChannel from '../Structures/channels/News.js'
|
|
||||||
import PrivateChannel from '../Structures/channels/Private.js'
|
|
||||||
import StageChannel from '../Structures/channels/Stage.js'
|
|
||||||
import TextChannel from '../Structures/channels/Text.js'
|
|
||||||
import TextVoiceChannel from '../Structures/channels/TextVoice.js'
|
|
||||||
import NewsThreadChannel from '../Structures/channels/threads/NewsThread.js'
|
|
||||||
import PrivateThreadChannel from '../Structures/channels/threads/PrivateThread.js'
|
|
||||||
import PublicThreadChannel from '../Structures/channels/threads/PublicThread.js'
|
|
||||||
import AutocompleteInteraction from '../Structures/interactions/Autocomplete.js'
|
|
||||||
import CommandInteraction from '../Structures/interactions/Command.js'
|
|
||||||
import ComponentInteraction from '../Structures/interactions/Component.js'
|
|
||||||
import PingInteraction from '../Structures/interactions/Ping.js'
|
|
||||||
import UnknownInteraction from '../Structures/interactions/Unknown.js'
|
|
||||||
|
|
||||||
export function generateChannelFrom(data: DiscordChannel, client: Client): Channel {
|
|
||||||
switch (data.type) {
|
|
||||||
case ChannelTypes.GuildText: {
|
|
||||||
return new TextChannel(data, client)
|
|
||||||
}
|
|
||||||
case ChannelTypes.DM: {
|
|
||||||
return new PrivateChannel(data, client)
|
|
||||||
}
|
|
||||||
case ChannelTypes.GuildVoice: {
|
|
||||||
return new TextVoiceChannel(data, client)
|
|
||||||
}
|
|
||||||
case ChannelTypes.GuildCategory: {
|
|
||||||
return new CategoryChannel(data, client)
|
|
||||||
}
|
|
||||||
case ChannelTypes.GuildAnnouncement: {
|
|
||||||
return new NewsChannel(data, client)
|
|
||||||
}
|
|
||||||
case ChannelTypes.AnnouncementThread: {
|
|
||||||
return new NewsThreadChannel(data, client)
|
|
||||||
}
|
|
||||||
case ChannelTypes.PublicThread: {
|
|
||||||
return new PublicThreadChannel(data, client)
|
|
||||||
}
|
|
||||||
case ChannelTypes.PrivateThread: {
|
|
||||||
return new PrivateThreadChannel(data, client)
|
|
||||||
}
|
|
||||||
case ChannelTypes.GuildStageVoice: {
|
|
||||||
return new StageChannel(data, client)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (data.guild_id) {
|
|
||||||
if (data.last_message_id !== undefined) {
|
|
||||||
client.emit('warn', new Error(`Unknown guild text channel type: ${data.type}\n${JSON.stringify(data)}`))
|
|
||||||
return new TextChannel(data, client)
|
|
||||||
}
|
|
||||||
client.emit('warn', new Error(`Unknown guild channel type: ${data.type}\n${JSON.stringify(data)}`))
|
|
||||||
return new GuildChannel(data, client)
|
|
||||||
}
|
|
||||||
client.emit('warn', new Error(`Unknown channel type: ${data.type}\n${JSON.stringify(data)}`))
|
|
||||||
return new Channel(data, client)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function generateInteractionFrom(
|
|
||||||
data: DiscordInteraction,
|
|
||||||
client: Client,
|
|
||||||
): UnknownInteraction<TextableChannel> | PingInteraction | CommandInteraction | ComponentInteraction | AutocompleteInteraction {
|
|
||||||
switch (data.type) {
|
|
||||||
case InteractionTypes.Ping: {
|
|
||||||
return new PingInteraction(data, client)
|
|
||||||
}
|
|
||||||
case InteractionTypes.ApplicationCommand: {
|
|
||||||
return new CommandInteraction(data, client)
|
|
||||||
}
|
|
||||||
case InteractionTypes.MessageComponent: {
|
|
||||||
return new ComponentInteraction(data, client)
|
|
||||||
}
|
|
||||||
case InteractionTypes.ApplicationCommandAutocomplete: {
|
|
||||||
return new AutocompleteInteraction(data, client)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
client.emit('warn', new Error(`Unknown interaction type: ${data.type}\n${JSON.stringify(data)}`))
|
|
||||||
return new UnknownInteraction(data, client)
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import { describe, it } from 'mocha'
|
|
||||||
|
|
||||||
describe('index.ts', () => {
|
|
||||||
it('will import without error', async () => {
|
|
||||||
await import('../src/index.js')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "tsconfig/test.json",
|
|
||||||
"include": [
|
|
||||||
"tests",
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"node_modules",
|
|
||||||
"dist",
|
|
||||||
"src"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
camelToSnakeCase,
|
camelToSnakeCase,
|
||||||
delay,
|
delay,
|
||||||
encode,
|
encode,
|
||||||
findFiles,
|
|
||||||
getBotIdFromToken,
|
getBotIdFromToken,
|
||||||
isGetMessagesAfter,
|
isGetMessagesAfter,
|
||||||
isGetMessagesAround,
|
isGetMessagesAround,
|
||||||
@@ -33,7 +32,6 @@ import type {
|
|||||||
DiscordBan,
|
DiscordBan,
|
||||||
DiscordChannel,
|
DiscordChannel,
|
||||||
DiscordEmoji,
|
DiscordEmoji,
|
||||||
DiscordFollowAnnouncementChannel,
|
|
||||||
DiscordFollowedChannel,
|
DiscordFollowedChannel,
|
||||||
DiscordGetGatewayBot,
|
DiscordGetGatewayBot,
|
||||||
DiscordGuild,
|
DiscordGuild,
|
||||||
@@ -67,7 +65,7 @@ import type {
|
|||||||
MfaLevels,
|
MfaLevels,
|
||||||
ModifyGuildTemplate,
|
ModifyGuildTemplate,
|
||||||
} from '@discordeno/types'
|
} from '@discordeno/types'
|
||||||
import type { CreateRestManagerOptions, RestManager, SendRequestOptions } from './types.js'
|
import type { CreateRequestBodyOptions, CreateRestManagerOptions, RestManager, SendRequestOptions } from './types.js'
|
||||||
|
|
||||||
// TODO: make dynamic based on package.json file
|
// TODO: make dynamic based on package.json file
|
||||||
const version = '19.0.0-alpha.1'
|
const version = '19.0.0-alpha.1'
|
||||||
@@ -693,62 +691,54 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
|||||||
return obj
|
return obj
|
||||||
},
|
},
|
||||||
|
|
||||||
createRequest(options) {
|
createRequestBody(method, options) {
|
||||||
const headers: Record<string, string> = {
|
const headers: Record<string, string> = {
|
||||||
'user-agent': `DiscordBot (https://github.com/discordeno/discordeno, v${version})`,
|
'user-agent': `DiscordBot (https://github.com/discordeno/discordeno, v${version})`,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.unauthorized) headers.authorization = `Bot ${rest.token}`
|
if (!options?.unauthorized) headers.authorization = `Bot ${rest.token}`
|
||||||
|
|
||||||
// SOMETIMES SPECIAL HEADERS (E.G. CUSTOM AUTHORIZATION) NEED TO BE USED
|
|
||||||
if (options.headers) {
|
|
||||||
for (const key in options.headers) {
|
|
||||||
headers[key.toLowerCase()] = options.headers[key]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GET METHODS SHOULD NOT HAVE A BODY
|
|
||||||
if (options.method === 'GET') {
|
|
||||||
options.body = undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
// IF A REASON IS PROVIDED ENCODE IT IN HEADERS
|
// IF A REASON IS PROVIDED ENCODE IT IN HEADERS
|
||||||
if (options.body?.reason) {
|
if (options?.reason !== undefined) {
|
||||||
headers['X-Audit-Log-Reason'] = encodeURIComponent(options.body.reason as string)
|
headers['x-audit-log-reason'] = encodeURIComponent(options?.reason)
|
||||||
options.body.reason = undefined
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.body) {
|
let body: string | FormData | undefined
|
||||||
const { file } = options.body
|
|
||||||
if (file) {
|
|
||||||
const files = findFiles(file)
|
|
||||||
const form = new FormData()
|
|
||||||
|
|
||||||
// WHEN CREATING A STICKER, DISCORD WANTS FORM DATA ONLY
|
// TODO: check if we need to add specific check for GET method
|
||||||
if (options.url?.endsWith('/stickers') && options.method === 'POST') {
|
// Since GET does not allow bodies
|
||||||
form.append('file', files[0].blob, files[0].name)
|
|
||||||
form.append('name', options.body.name as string)
|
|
||||||
form.append('description', options.body.description as string)
|
|
||||||
form.append('tags', options.body.tags as string)
|
|
||||||
} else {
|
|
||||||
for (let i = 0; i < files.length; i++) {
|
|
||||||
form.append(`file${i}`, files[i].blob, files[i].name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file) options.body.file = undefined
|
// Have to check for attachments first, since body then has to be send in a different way.
|
||||||
form.append('payload_json', JSON.stringify(rest.changeToDiscordFormat(options.body)))
|
if (options?.files !== undefined) {
|
||||||
}
|
const form = new FormData()
|
||||||
|
for (let i = 0; i < options.files.length; ++i) {
|
||||||
options.body.file = form
|
form.append(`file${i}`, options.files[i].blob, options.files[i].name)
|
||||||
} else if (options.body && !['GET', 'DELETE'].includes(options.method)) {
|
|
||||||
headers['Content-Type'] = 'application/json'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
form.append('payload_json', JSON.stringify({ ...options.body, files: undefined }))
|
||||||
|
|
||||||
|
body = form
|
||||||
|
|
||||||
|
// No need to set the `content-type` header since `fetch` does that automatically for us when we use a `FormData` object.
|
||||||
|
} else if (options?.body !== undefined) {
|
||||||
|
if (options.body instanceof FormData) {
|
||||||
|
body = options.body
|
||||||
|
// No need to set the `content-type` header since `fetch` does that automatically for us when we use a `FormData` object.
|
||||||
|
} else {
|
||||||
|
body = JSON.stringify(rest.changeToDiscordFormat(options.body))
|
||||||
|
headers['content-type'] = `application/json`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SOMETIMES SPECIAL HEADERS (E.G. CUSTOM AUTHORIZATION) NEED TO BE USED
|
||||||
|
if (options?.headers) {
|
||||||
|
Object.assign(headers, options.headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
body,
|
||||||
headers,
|
headers,
|
||||||
body: (options.body?.file ?? JSON.stringify(rest.changeToDiscordFormat(options.body))) as FormData | string,
|
method,
|
||||||
method: options.method,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -860,7 +850,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
|||||||
|
|
||||||
async sendRequest(options) {
|
async sendRequest(options) {
|
||||||
const url = options.url.startsWith('https://') ? options.url : `${rest.baseUrl}/v${rest.version}${options.url}`
|
const url = options.url.startsWith('https://') ? options.url : `${rest.baseUrl}/v${rest.version}${options.url}`
|
||||||
const payload = rest.createRequest({ method: options.method, url: options.url, body: options.body, ...options.options })
|
const payload = rest.createRequestBody(options.method, options.requestBodyOptions)
|
||||||
|
|
||||||
logger.debug(`sending request to ${url}`, 'with payload:', { ...payload, headers: { ...payload.headers, authorization: 'Bot tokenhere' } })
|
logger.debug(`sending request to ${url}`, 'with payload:', { ...payload, headers: { ...payload.headers, authorization: 'Bot tokenhere' } })
|
||||||
const response = await fetch(url, payload)
|
const response = await fetch(url, payload)
|
||||||
@@ -909,26 +899,31 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
|||||||
options.resolve({ ok: true, status: response.status, body: JSON.stringify(json) })
|
options.resolve({ ok: true, status: response.status, body: JSON.stringify(json) })
|
||||||
},
|
},
|
||||||
|
|
||||||
// Credits: github.com/abalabahaha/eris lib/rest/RequestHandler.js#L397
|
|
||||||
// Modified for our use-case
|
|
||||||
simplifyUrl(url, method) {
|
simplifyUrl(url, method) {
|
||||||
let route = url
|
const parts = url.split('/')
|
||||||
.replace(/\/([a-z-]+)\/(?:[0-9]{17,19})/g, function (match, p: string) {
|
const secondLastPart = parts[parts.length - 2]
|
||||||
return ['channels', 'guilds'].includes(p) ? match : `/${p}/x`
|
|
||||||
})
|
|
||||||
.replace(/\/reactions\/[^/]+/g, '/reactions/x')
|
|
||||||
|
|
||||||
// GENERAL /reactions and /reactions/emoji/@me share the buckets
|
if (secondLastPart === 'channels' || secondLastPart === 'guilds') {
|
||||||
if (route.includes('/reactions')) {
|
return url
|
||||||
route = route.substring(0, route.indexOf('/reactions') + '/reactions'.length)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete Message endpoint has its own rate limit
|
if (secondLastPart === 'reactions' || parts[parts.length - 1] === '@me') {
|
||||||
if (method === 'DELETE' && route.endsWith('/messages/x')) {
|
parts.splice(-2)
|
||||||
route = method + route
|
parts.push('reactions')
|
||||||
|
} else {
|
||||||
|
parts.splice(-1)
|
||||||
|
parts.push('x')
|
||||||
}
|
}
|
||||||
|
|
||||||
return route
|
if (parts[parts.length - 3] === 'reactions') {
|
||||||
|
parts.splice(-2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method === 'DELETE' && secondLastPart === 'messages') {
|
||||||
|
return `D${parts.join('/')}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.join('/')
|
||||||
},
|
},
|
||||||
|
|
||||||
processRequest(request: SendRequestOptions) {
|
processRequest(request: SendRequestOptions) {
|
||||||
@@ -957,16 +952,17 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async makeRequest(method, url, body, options) {
|
async makeRequest(method, url, options) {
|
||||||
if (!rest.baseUrl.startsWith('https://discord.com') && url[0] === '/') {
|
if (!rest.baseUrl.startsWith('https://discord.com') && url[0] === '/') {
|
||||||
// Special handling for sending blobs across http to proxy
|
// Special handling for sending blobs across http to proxy
|
||||||
if (body?.file) {
|
// TODO: fix this hacky handling
|
||||||
if (!Array.isArray(body.file)) {
|
if (!(options?.body instanceof FormData) && !Array.isArray(options?.body) && options?.body?.file) {
|
||||||
body.file = [body.file]
|
if (!Array.isArray(options.body.file)) {
|
||||||
|
options.body.file = [options.body.file]
|
||||||
}
|
}
|
||||||
// convert blobs to string before sending to proxy
|
// convert blobs to string before sending to proxy
|
||||||
body.file = await Promise.all(
|
options.body.file = await Promise.all(
|
||||||
body.file.map(async (f: FileContent) => {
|
(options.body.file as FileContent[]).map(async (f: FileContent) => {
|
||||||
const url = encode(await f.blob.arrayBuffer())
|
const url = encode(await f.blob.arrayBuffer())
|
||||||
|
|
||||||
return { name: f.name, blob: `data:${f.blob.type};base64,${url}` }
|
return { name: f.name, blob: `data:${f.blob.type};base64,${url}` }
|
||||||
@@ -977,17 +973,18 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
|||||||
const headers: HeadersInit = {
|
const headers: HeadersInit = {
|
||||||
Authorization: rest.authorization ?? '',
|
Authorization: rest.authorization ?? '',
|
||||||
}
|
}
|
||||||
if (body) {
|
if (options?.body) {
|
||||||
headers['Content-Type'] = 'application/json'
|
headers['Content-Type'] = 'application/json'
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await fetch(`${rest.baseUrl}${url}`, {
|
const result = await fetch(`${rest.baseUrl}${url}`, {
|
||||||
body: body ? JSON.stringify(body) : undefined,
|
body: options?.body ? JSON.stringify(options.body) : undefined,
|
||||||
headers,
|
headers,
|
||||||
method,
|
method,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!result.ok) {
|
if (!result.ok) {
|
||||||
const err = (await result.json().catch(() => {})) as Record<string, any>
|
const err = (await result.json().catch(() => { })) as Record<string, any>
|
||||||
// Legacy Handling to not break old code or when body is missing
|
// Legacy Handling to not break old code or when body is missing
|
||||||
if (!err?.body) throw new Error(`Error: ${err.message ?? result.statusText}`)
|
if (!err?.body) throw new Error(`Error: ${err.message ?? result.statusText}`)
|
||||||
throw new Error(JSON.stringify(err))
|
throw new Error(JSON.stringify(err))
|
||||||
@@ -1000,40 +997,39 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
|||||||
const payload: SendRequestOptions = {
|
const payload: SendRequestOptions = {
|
||||||
url,
|
url,
|
||||||
method,
|
method,
|
||||||
body,
|
requestBodyOptions: options,
|
||||||
retryCount: 0,
|
retryCount: 0,
|
||||||
retryRequest: async function (options: SendRequestOptions) {
|
retryRequest: async function(payload: SendRequestOptions) {
|
||||||
rest.processRequest(payload)
|
rest.processRequest(payload)
|
||||||
},
|
},
|
||||||
resolve: (data) => {
|
resolve: (data) => {
|
||||||
resolve(data.status !== 204 ? JSON.parse(data.body ?? '{}') : undefined)
|
resolve(data.status !== 204 ? JSON.parse(data.body ?? '{}') : undefined)
|
||||||
},
|
},
|
||||||
reject,
|
reject,
|
||||||
options,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rest.processRequest(payload)
|
rest.processRequest(payload)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
async get<T = Record<string, unknown>>(url: string) {
|
async get<T = Record<string, unknown>>(url: string, options?: Omit<CreateRequestBodyOptions, 'body' | 'method'>) {
|
||||||
return camelize(await rest.makeRequest('GET', url)) as Camelize<T>
|
return camelize(await rest.makeRequest('GET', url, options)) as Camelize<T>
|
||||||
},
|
},
|
||||||
|
|
||||||
async post<T = Record<string, unknown>>(url: string, body?: Record<string, any>) {
|
async post<T = Record<string, unknown>>(url: string, options?: Omit<CreateRequestBodyOptions, 'body' | 'method'>) {
|
||||||
return camelize(await rest.makeRequest('POST', url, body)) as Camelize<T>
|
return camelize(await rest.makeRequest('POST', url, options)) as Camelize<T>
|
||||||
},
|
},
|
||||||
|
|
||||||
async delete(url: string, body?: Record<string, any>) {
|
async delete(url: string, options?: Omit<CreateRequestBodyOptions, 'body' | 'method'>) {
|
||||||
camelize(await rest.makeRequest('DELETE', url, body))
|
camelize(await rest.makeRequest('DELETE', url, options))
|
||||||
},
|
},
|
||||||
|
|
||||||
async patch<T = Record<string, unknown>>(url: string, body?: Record<string, any>) {
|
async patch<T = Record<string, unknown>>(url: string, options?: Omit<CreateRequestBodyOptions, 'body' | 'method'>) {
|
||||||
return camelize(await rest.makeRequest('PATCH', url, body)) as Camelize<T>
|
return camelize(await rest.makeRequest('PATCH', url, options)) as Camelize<T>
|
||||||
},
|
},
|
||||||
|
|
||||||
async put<T = void>(url: string, body?: Record<string, any>, options?: Record<string, any>) {
|
async put<T = void>(url: string, options?: Omit<CreateRequestBodyOptions, 'body' | 'method'>) {
|
||||||
return camelize(await rest.makeRequest('PUT', url, body, options)) as Camelize<T>
|
return camelize(await rest.makeRequest('PUT', url, options)) as Camelize<T>
|
||||||
},
|
},
|
||||||
|
|
||||||
async addReaction(channelId, messageId, reaction) {
|
async addReaction(channelId, messageId, reaction) {
|
||||||
@@ -1065,74 +1061,79 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
|||||||
await rest.put(rest.routes.channels.threads.user(channelId, userId))
|
await rest.put(rest.routes.channels.threads.user(channelId, userId))
|
||||||
},
|
},
|
||||||
|
|
||||||
async createAutomodRule(guildId, options) {
|
async createAutomodRule(guildId, body) {
|
||||||
return await rest.post<DiscordAutoModerationRule>(rest.routes.guilds.automod.rules(guildId), options)
|
return await rest.post<DiscordAutoModerationRule>(rest.routes.guilds.automod.rules(guildId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async createChannel(guildId, options) {
|
async createChannel(guildId, body) {
|
||||||
return await rest.post<DiscordChannel>(rest.routes.guilds.channels(guildId), options)
|
return await rest.post<DiscordChannel>(rest.routes.guilds.channels(guildId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async createEmoji(guildId, options) {
|
async createEmoji(guildId, body) {
|
||||||
return await rest.post<DiscordEmoji>(rest.routes.guilds.emojis(guildId), options)
|
return await rest.post<DiscordEmoji>(rest.routes.guilds.emojis(guildId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async createGlobalApplicationCommand(command) {
|
async createGlobalApplicationCommand(body) {
|
||||||
return await rest.post<DiscordApplicationCommand>(rest.routes.interactions.commands.commands(rest.applicationId), command)
|
return await rest.post<DiscordApplicationCommand>(rest.routes.interactions.commands.commands(rest.applicationId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async createGuild(options) {
|
async createGuild(body) {
|
||||||
return await rest.post<DiscordGuild>(rest.routes.guilds.all(), options)
|
return await rest.post<DiscordGuild>(rest.routes.guilds.all(), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async createGuildApplicationCommand(command, guildId) {
|
async createGuildApplicationCommand(body, guildId) {
|
||||||
return await rest.post<DiscordApplicationCommand>(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), command)
|
return await rest.post<DiscordApplicationCommand>(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async createGuildFromTemplate(templateCode, options) {
|
async createGuildFromTemplate(templateCode, body) {
|
||||||
if (options.icon) {
|
if (body.icon) {
|
||||||
options.icon = await urlToBase64(options.icon)
|
body.icon = await urlToBase64(body.icon)
|
||||||
}
|
}
|
||||||
|
|
||||||
return await rest.post<DiscordGuild>(rest.routes.guilds.templates.code(templateCode), options)
|
return await rest.post<DiscordGuild>(rest.routes.guilds.templates.code(templateCode), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async createGuildSticker(guildId, options) {
|
async createGuildSticker(guildId, options) {
|
||||||
return await rest.post<DiscordSticker>(rest.routes.guilds.stickers(guildId), options)
|
const form = new FormData()
|
||||||
|
form.append('file', options.file.blob, options.file.name)
|
||||||
|
form.append('name', options.name)
|
||||||
|
form.append('description', options.description)
|
||||||
|
form.append('tags', options.tags)
|
||||||
|
|
||||||
|
return await rest.post<DiscordSticker>(rest.routes.guilds.stickers(guildId), { body: form })
|
||||||
},
|
},
|
||||||
|
|
||||||
async createGuildTemplate(guildId, options) {
|
async createGuildTemplate(guildId, body) {
|
||||||
return await rest.post<DiscordTemplate>(rest.routes.guilds.templates.all(guildId), options)
|
return await rest.post<DiscordTemplate>(rest.routes.guilds.templates.all(guildId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async createForumThread(channelId, options) {
|
async createForumThread(channelId, body) {
|
||||||
return await rest.post<DiscordChannel>(rest.routes.channels.forum(channelId), options)
|
return await rest.post<DiscordChannel>(rest.routes.channels.forum(channelId), { body, files: body.files })
|
||||||
},
|
},
|
||||||
|
|
||||||
async createInvite(channelId, options = {}) {
|
async createInvite(channelId, body = {}) {
|
||||||
return await rest.post<DiscordInvite>(rest.routes.channels.invites(channelId), options)
|
return await rest.post<DiscordInvite>(rest.routes.channels.invites(channelId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async createRole(guildId, options, reason) {
|
async createRole(guildId, body, reason) {
|
||||||
return await rest.post<DiscordRole>(rest.routes.guilds.roles.all(guildId), {
|
return await rest.post<DiscordRole>(rest.routes.guilds.roles.all(guildId), { body, reason })
|
||||||
...options,
|
|
||||||
reason,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async createScheduledEvent(guildId, options) {
|
async createScheduledEvent(guildId, body) {
|
||||||
return await rest.post<DiscordScheduledEvent>(rest.routes.guilds.events.events(guildId), options)
|
return await rest.post<DiscordScheduledEvent>(rest.routes.guilds.events.events(guildId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async createStageInstance(options) {
|
async createStageInstance(body) {
|
||||||
return await rest.post<DiscordStageInstance>(rest.routes.channels.stages(), options)
|
return await rest.post<DiscordStageInstance>(rest.routes.channels.stages(), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async createWebhook(channelId, options) {
|
async createWebhook(channelId, options, reason) {
|
||||||
return await rest.post<DiscordWebhook>(rest.routes.channels.webhooks(channelId), {
|
return await rest.post<DiscordWebhook>(rest.routes.channels.webhooks(channelId), {
|
||||||
name: options.name,
|
body: {
|
||||||
avatar: options.avatar ? await urlToBase64(options.avatar) : undefined,
|
name: options.name,
|
||||||
reason: options.reason,
|
avatar: options.avatar ? await urlToBase64(options.avatar) : undefined,
|
||||||
|
},
|
||||||
|
reason,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1147,7 +1148,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
|||||||
},
|
},
|
||||||
|
|
||||||
async deleteChannelPermissionOverride(channelId, overwriteId, reason) {
|
async deleteChannelPermissionOverride(channelId, overwriteId, reason) {
|
||||||
await rest.delete(rest.routes.channels.overwrite(channelId, overwriteId), reason ? { reason } : undefined)
|
await rest.delete(rest.routes.channels.overwrite(channelId, overwriteId), { reason })
|
||||||
},
|
},
|
||||||
|
|
||||||
async deleteEmoji(guildId, id, reason) {
|
async deleteEmoji(guildId, id, reason) {
|
||||||
@@ -1171,7 +1172,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
|||||||
},
|
},
|
||||||
|
|
||||||
async deleteGuildSticker(guildId, stickerId, reason) {
|
async deleteGuildSticker(guildId, stickerId, reason) {
|
||||||
await rest.delete(rest.routes.guilds.sticker(guildId, stickerId), reason ? { reason } : undefined)
|
await rest.delete(rest.routes.guilds.sticker(guildId, stickerId), { reason })
|
||||||
},
|
},
|
||||||
|
|
||||||
async deleteGuildTemplate(guildId, templateCode) {
|
async deleteGuildTemplate(guildId, templateCode) {
|
||||||
@@ -1183,7 +1184,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
|||||||
},
|
},
|
||||||
|
|
||||||
async deleteInvite(inviteCode, reason) {
|
async deleteInvite(inviteCode, reason) {
|
||||||
await rest.delete(rest.routes.guilds.invite(inviteCode), reason ? { reason } : undefined)
|
await rest.delete(rest.routes.guilds.invite(inviteCode), { reason })
|
||||||
},
|
},
|
||||||
|
|
||||||
async deleteMessage(channelId, messageId, reason) {
|
async deleteMessage(channelId, messageId, reason) {
|
||||||
@@ -1192,7 +1193,9 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
|||||||
|
|
||||||
async deleteMessages(channelId, messageIds, reason) {
|
async deleteMessages(channelId, messageIds, reason) {
|
||||||
await rest.post(rest.routes.channels.bulk(channelId), {
|
await rest.post(rest.routes.channels.bulk(channelId), {
|
||||||
messages: messageIds.slice(0, 100).map((id) => id.toString()),
|
body: {
|
||||||
|
messages: messageIds.slice(0, 100).map((id) => id.toString()),
|
||||||
|
},
|
||||||
reason,
|
reason,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -1226,7 +1229,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
|||||||
},
|
},
|
||||||
|
|
||||||
async deleteStageInstance(channelId, reason) {
|
async deleteStageInstance(channelId, reason) {
|
||||||
await rest.delete(rest.routes.channels.stage(channelId), reason ? { reason } : undefined)
|
await rest.delete(rest.routes.channels.stage(channelId), { reason })
|
||||||
},
|
},
|
||||||
|
|
||||||
async deleteUserReaction(channelId, messageId, userId, reaction) {
|
async deleteUserReaction(channelId, messageId, userId, reaction) {
|
||||||
@@ -1247,155 +1250,167 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
|||||||
await rest.delete(rest.routes.webhooks.webhook(webhookId, token))
|
await rest.delete(rest.routes.webhooks.webhook(webhookId, token))
|
||||||
},
|
},
|
||||||
|
|
||||||
async editApplicationCommandPermissions(guildId, commandId, bearerToken, options) {
|
async editApplicationCommandPermissions(guildId, commandId, bearerToken, permissions) {
|
||||||
return await rest.put<DiscordApplicationCommandPermissions>(
|
return await rest.put<DiscordApplicationCommandPermissions>(
|
||||||
rest.routes.interactions.commands.permission(rest.applicationId, guildId, commandId),
|
rest.routes.interactions.commands.permission(rest.applicationId, guildId, commandId),
|
||||||
{
|
{
|
||||||
permissions: options,
|
body: {
|
||||||
},
|
permissions,
|
||||||
{
|
},
|
||||||
headers: { authorization: `Bearer ${bearerToken}` },
|
headers: { authorization: `Bearer ${bearerToken}` },
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
async editAutomodRule(guildId, ruleId, options) {
|
async editAutomodRule(guildId, ruleId, body) {
|
||||||
return await rest.patch<DiscordAutoModerationRule>(rest.routes.guilds.automod.rule(guildId, ruleId), options)
|
return await rest.patch<DiscordAutoModerationRule>(rest.routes.guilds.automod.rule(guildId, ruleId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editBotProfile(options) {
|
async editBotProfile(options) {
|
||||||
const avatar = options?.botAvatarURL ? await urlToBase64(options?.botAvatarURL) : options?.botAvatarURL
|
const avatar = options?.botAvatarURL ? await urlToBase64(options?.botAvatarURL) : options?.botAvatarURL
|
||||||
|
|
||||||
return await rest.patch<DiscordUser>(rest.routes.userBot(), {
|
return await rest.patch<DiscordUser>(rest.routes.userBot(), {
|
||||||
username: options.username?.trim(),
|
body: {
|
||||||
avatar,
|
username: options.username?.trim(),
|
||||||
|
avatar,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
async editChannel(channelId, options) {
|
async editChannel(channelId, body) {
|
||||||
return await rest.patch<DiscordChannel>(rest.routes.channels.channel(channelId), options)
|
return await rest.patch<DiscordChannel>(rest.routes.channels.channel(channelId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editChannelPermissionOverrides(channelId, options) {
|
async editChannelPermissionOverrides(channelId, body) {
|
||||||
await rest.put(rest.routes.channels.overwrite(channelId, options.id), options)
|
await rest.put(rest.routes.channels.overwrite(channelId, body.id), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editChannelPositions(guildId, channelPositions) {
|
async editChannelPositions(guildId, body) {
|
||||||
await rest.patch(rest.routes.guilds.channels(guildId), channelPositions)
|
await rest.patch(rest.routes.guilds.channels(guildId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editEmoji(guildId, id, options) {
|
async editEmoji(guildId, id, body) {
|
||||||
return await rest.patch<DiscordEmoji>(rest.routes.guilds.emoji(guildId, id), options)
|
return await rest.patch<DiscordEmoji>(rest.routes.guilds.emoji(guildId, id), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editFollowupMessage(token, messageId, options) {
|
async editFollowupMessage(token, messageId, body) {
|
||||||
return await rest.patch<DiscordMessage>(rest.routes.interactions.responses.message(rest.applicationId, token, messageId), options)
|
return await rest.patch<DiscordMessage>(rest.routes.interactions.responses.message(rest.applicationId, token, messageId), {
|
||||||
|
body,
|
||||||
|
files: body.files,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
async editGlobalApplicationCommand(commandId, options) {
|
async editGlobalApplicationCommand(commandId, body) {
|
||||||
return await rest.patch<DiscordApplicationCommand>(rest.routes.interactions.commands.command(rest.applicationId, commandId), options)
|
return await rest.patch<DiscordApplicationCommand>(rest.routes.interactions.commands.command(rest.applicationId, commandId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editGuild(guildId, options) {
|
async editGuild(guildId, body) {
|
||||||
return await rest.patch<DiscordGuild>(rest.routes.guilds.guild(guildId), options)
|
return await rest.patch<DiscordGuild>(rest.routes.guilds.guild(guildId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editGuildApplicationCommand(commandId, guildId, options) {
|
async editGuildApplicationCommand(commandId, guildId, body) {
|
||||||
return await rest.patch<DiscordApplicationCommand>(
|
return await rest.patch<DiscordApplicationCommand>(rest.routes.interactions.commands.guilds.one(rest.applicationId, guildId, commandId), {
|
||||||
rest.routes.interactions.commands.guilds.one(rest.applicationId, guildId, commandId),
|
body,
|
||||||
options,
|
})
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async editGuildMfaLevel(guildId: BigString, mfaLevel: MfaLevels, reason?: string): Promise<void> {
|
async editGuildMfaLevel(guildId: BigString, mfaLevel: MfaLevels, reason?: string): Promise<void> {
|
||||||
await rest.post(rest.routes.guilds.mfa(guildId), { level: mfaLevel, reason })
|
await rest.post(rest.routes.guilds.mfa(guildId), { body: { level: mfaLevel }, reason })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editGuildSticker(guildId, stickerId, options) {
|
async editGuildSticker(guildId, stickerId, body) {
|
||||||
return await rest.patch<DiscordSticker>(rest.routes.guilds.sticker(guildId, stickerId), options)
|
return await rest.patch<DiscordSticker>(rest.routes.guilds.sticker(guildId, stickerId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editGuildTemplate(guildId, templateCode: string, options: ModifyGuildTemplate): Promise<Camelize<DiscordTemplate>> {
|
async editGuildTemplate(guildId, templateCode: string, body: ModifyGuildTemplate): Promise<Camelize<DiscordTemplate>> {
|
||||||
return await rest.patch<DiscordTemplate>(rest.routes.guilds.templates.guild(guildId, templateCode), options)
|
return await rest.patch<DiscordTemplate>(rest.routes.guilds.templates.guild(guildId, templateCode), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editMessage(channelId, messageId, options) {
|
async editMessage(channelId, messageId, body) {
|
||||||
return await rest.patch<DiscordMessage>(rest.routes.channels.message(channelId, messageId), options)
|
return await rest.patch<DiscordMessage>(rest.routes.channels.message(channelId, messageId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editOriginalInteractionResponse(token, options) {
|
async editOriginalInteractionResponse(token, body) {
|
||||||
return await rest.patch<DiscordMessage>(rest.routes.interactions.responses.original(rest.applicationId, token), options)
|
return await rest.patch<DiscordMessage>(rest.routes.interactions.responses.original(rest.applicationId, token), {
|
||||||
|
body,
|
||||||
|
files: body.files,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
async editOriginalWebhookMessage(webhookId, token, options) {
|
async editOriginalWebhookMessage(webhookId, token, options) {
|
||||||
return await rest.patch<DiscordMessage>(rest.routes.webhooks.original(webhookId, token, options), {
|
return await rest.patch<DiscordMessage>(rest.routes.webhooks.original(webhookId, token, options), {
|
||||||
type: InteractionResponseTypes.UpdateMessage,
|
body: {
|
||||||
data: options,
|
type: InteractionResponseTypes.UpdateMessage,
|
||||||
|
data: options,
|
||||||
|
},
|
||||||
|
files: options.files,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
async editOwnVoiceState(guildId, options) {
|
async editOwnVoiceState(guildId, options) {
|
||||||
await rest.patch(rest.routes.guilds.voice(guildId), {
|
await rest.patch(rest.routes.guilds.voice(guildId), {
|
||||||
channel_id: options.channelId,
|
body: {
|
||||||
suppress: options.suppress,
|
...options,
|
||||||
request_to_speak_timestamp: options.requestToSpeakTimestamp
|
request_to_speak_timestamp: options.requestToSpeakTimestamp
|
||||||
? new Date(options.requestToSpeakTimestamp).toISOString()
|
? new Date(options.requestToSpeakTimestamp).toISOString()
|
||||||
: options.requestToSpeakTimestamp,
|
: options.requestToSpeakTimestamp,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
async editScheduledEvent(guildId, eventId, options) {
|
async editScheduledEvent(guildId, eventId, body) {
|
||||||
return await rest.patch<DiscordScheduledEvent>(rest.routes.guilds.events.event(guildId, eventId), options)
|
return await rest.patch<DiscordScheduledEvent>(rest.routes.guilds.events.event(guildId, eventId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editRole(guildId, roleId, options) {
|
async editRole(guildId, roleId, body) {
|
||||||
return await rest.patch<DiscordRole>(rest.routes.guilds.roles.one(guildId, roleId), options)
|
return await rest.patch<DiscordRole>(rest.routes.guilds.roles.one(guildId, roleId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editRolePositions(guildId, options) {
|
async editRolePositions(guildId, body) {
|
||||||
return await rest.patch<DiscordRole[]>(rest.routes.guilds.roles.all(guildId), options)
|
return await rest.patch<DiscordRole[]>(rest.routes.guilds.roles.all(guildId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editStageInstance(channelId, data) {
|
async editStageInstance(channelId, topic, reason?: string) {
|
||||||
return await rest.patch<DiscordStageInstance>(rest.routes.channels.stage(channelId), { topic: data.topic })
|
return await rest.patch<DiscordStageInstance>(rest.routes.channels.stage(channelId), { body: { topic }, reason })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editUserVoiceState(guildId, options) {
|
async editUserVoiceState(guildId, options) {
|
||||||
await rest.patch(rest.routes.guilds.voice(guildId, options.userId), {
|
await rest.patch(rest.routes.guilds.voice(guildId, options.userId), { body: options })
|
||||||
channel_id: options.channelId,
|
|
||||||
suppress: options.suppress,
|
|
||||||
user_id: options.userId,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async editWebhook(webhookId, options) {
|
async editWebhook(webhookId, body) {
|
||||||
return await rest.patch<DiscordWebhook>(rest.routes.webhooks.id(webhookId), options)
|
return await rest.patch<DiscordWebhook>(rest.routes.webhooks.id(webhookId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editWebhookMessage(webhookId, token, messageId, options) {
|
async editWebhookMessage(webhookId, token, messageId, options) {
|
||||||
return await rest.patch<DiscordMessage>(rest.routes.webhooks.message(webhookId, token, messageId, options), options)
|
return await rest.patch<DiscordMessage>(rest.routes.webhooks.message(webhookId, token, messageId, options), {
|
||||||
|
body: options,
|
||||||
|
files: options.files,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
async editWebhookWithToken(webhookId, token, options) {
|
async editWebhookWithToken(webhookId, token, body) {
|
||||||
return await rest.patch<DiscordWebhook>(rest.routes.webhooks.webhook(webhookId, token), options)
|
return await rest.patch<DiscordWebhook>(rest.routes.webhooks.webhook(webhookId, token), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editWelcomeScreen(guildId, options) {
|
async editWelcomeScreen(guildId, body) {
|
||||||
return await rest.patch<DiscordWelcomeScreen>(rest.routes.guilds.welcome(guildId), options)
|
return await rest.patch<DiscordWelcomeScreen>(rest.routes.guilds.welcome(guildId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editWidgetSettings(guildId, options) {
|
async editWidgetSettings(guildId, body) {
|
||||||
return await rest.patch<DiscordGuildWidgetSettings>(rest.routes.guilds.widget(guildId), options)
|
return await rest.patch<DiscordGuildWidgetSettings>(rest.routes.guilds.widget(guildId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async executeWebhook(webhookId, token, options) {
|
async executeWebhook(webhookId, token, options) {
|
||||||
return await rest.post<DiscordMessage>(rest.routes.webhooks.webhook(webhookId, token, options), options)
|
return await rest.post<DiscordMessage>(rest.routes.webhooks.webhook(webhookId, token, options), { body: options })
|
||||||
},
|
},
|
||||||
|
|
||||||
async followAnnouncement(sourceChannelId, targetChannelId) {
|
async followAnnouncement(sourceChannelId, targetChannelId) {
|
||||||
return await rest.post<DiscordFollowedChannel>(rest.routes.channels.follow(sourceChannelId), {
|
return await rest.post<DiscordFollowedChannel>(rest.routes.channels.follow(sourceChannelId), {
|
||||||
webhook_channel_id: targetChannelId,
|
body: {
|
||||||
} as DiscordFollowAnnouncementChannel)
|
webhook_channel_id: targetChannelId,
|
||||||
|
},
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
async getActiveThreads(guildId) {
|
async getActiveThreads(guildId) {
|
||||||
@@ -1458,7 +1473,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
|||||||
|
|
||||||
async getDmChannel(userId) {
|
async getDmChannel(userId) {
|
||||||
return await rest.post<DiscordChannel>(rest.routes.channels.dm(), {
|
return await rest.post<DiscordChannel>(rest.routes.channels.dm(), {
|
||||||
recipient_id: userId.toString(),
|
body: { recipient_id: userId },
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1670,14 +1685,15 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
|||||||
await rest.delete(rest.routes.channels.threads.user(channelId, userId))
|
await rest.delete(rest.routes.channels.threads.user(channelId, userId))
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// TODO: why that
|
||||||
async sendFollowupMessage(token, options) {
|
async sendFollowupMessage(token, options) {
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
rest.sendRequest({
|
rest.sendRequest({
|
||||||
url: rest.routes.webhooks.webhook(rest.applicationId, token),
|
url: rest.routes.webhooks.webhook(rest.applicationId, token),
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: options,
|
requestBodyOptions: { body: options, files: options.files },
|
||||||
retryCount: 0,
|
retryCount: 0,
|
||||||
retryRequest: async function (options: SendRequestOptions) {
|
retryRequest: async function(options: SendRequestOptions) {
|
||||||
// TODO: should change to reprocess queue item
|
// TODO: should change to reprocess queue item
|
||||||
await rest.sendRequest(options)
|
await rest.sendRequest(options)
|
||||||
},
|
},
|
||||||
@@ -1689,14 +1705,15 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// TODO: why that
|
||||||
async sendInteractionResponse(interactionId, token, options) {
|
async sendInteractionResponse(interactionId, token, options) {
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
rest.sendRequest({
|
rest.sendRequest({
|
||||||
url: rest.routes.interactions.responses.callback(interactionId, token),
|
url: rest.routes.interactions.responses.callback(interactionId, token),
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: options,
|
requestBodyOptions: { body: options },
|
||||||
retryCount: 0,
|
retryCount: 0,
|
||||||
retryRequest: async function (options: SendRequestOptions) {
|
retryRequest: async function(options: SendRequestOptions) {
|
||||||
// TODO: should change to reprocess queue item
|
// TODO: should change to reprocess queue item
|
||||||
await rest.sendRequest(options)
|
await rest.sendRequest(options)
|
||||||
},
|
},
|
||||||
@@ -1708,32 +1725,32 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
async sendMessage(channelId, options) {
|
async sendMessage(channelId, body) {
|
||||||
return await rest.post<DiscordMessage>(rest.routes.channels.messages(channelId), options)
|
return await rest.post<DiscordMessage>(rest.routes.channels.messages(channelId), { body, files: body.files })
|
||||||
},
|
},
|
||||||
|
|
||||||
async startThreadWithMessage(channelId, messageId, options) {
|
async startThreadWithMessage(channelId, messageId, body) {
|
||||||
return await rest.post<DiscordChannel>(rest.routes.channels.threads.message(channelId, messageId), options)
|
return await rest.post<DiscordChannel>(rest.routes.channels.threads.message(channelId, messageId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async startThreadWithoutMessage(channelId, options) {
|
async startThreadWithoutMessage(channelId, body) {
|
||||||
return await rest.post<DiscordChannel>(rest.routes.channels.threads.all(channelId), options)
|
return await rest.post<DiscordChannel>(rest.routes.channels.threads.all(channelId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async syncGuildTemplate(guildId) {
|
async syncGuildTemplate(guildId) {
|
||||||
return await rest.put<DiscordTemplate>(rest.routes.guilds.templates.all(guildId))
|
return await rest.put<DiscordTemplate>(rest.routes.guilds.templates.all(guildId))
|
||||||
},
|
},
|
||||||
|
|
||||||
async banMember(guildId, userId, options) {
|
async banMember(guildId, userId, body) {
|
||||||
await rest.put<void>(rest.routes.guilds.members.ban(guildId, userId), options)
|
await rest.put<void>(rest.routes.guilds.members.ban(guildId, userId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editBotMember(guildId, options) {
|
async editBotMember(guildId, body) {
|
||||||
return await rest.patch<DiscordMember>(rest.routes.guilds.members.bot(guildId), options)
|
return await rest.patch<DiscordMember>(rest.routes.guilds.members.bot(guildId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async editMember(guildId, userId, options) {
|
async editMember(guildId, userId, body) {
|
||||||
return await rest.patch<DiscordMemberWithUser>(rest.routes.guilds.members.member(guildId, userId), options)
|
return await rest.patch<DiscordMemberWithUser>(rest.routes.guilds.members.member(guildId, userId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async getMember(guildId, userId) {
|
async getMember(guildId, userId) {
|
||||||
@@ -1751,11 +1768,11 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
|||||||
},
|
},
|
||||||
|
|
||||||
async pinMessage(channelId, messageId, reason) {
|
async pinMessage(channelId, messageId, reason) {
|
||||||
await rest.put(rest.routes.channels.pin(channelId, messageId), reason ? { reason } : undefined)
|
await rest.put(rest.routes.channels.pin(channelId, messageId), { reason })
|
||||||
},
|
},
|
||||||
|
|
||||||
async pruneMembers(guildId, options) {
|
async pruneMembers(guildId, body) {
|
||||||
return await rest.post<{ pruned: number | null }>(rest.routes.guilds.members.prune(guildId), options)
|
return await rest.post<{ pruned: number | null }>(rest.routes.guilds.members.prune(guildId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async searchMembers(guildId, query, options) {
|
async searchMembers(guildId, query, options) {
|
||||||
@@ -1767,19 +1784,19 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
|||||||
},
|
},
|
||||||
|
|
||||||
async unpinMessage(channelId, messageId, reason) {
|
async unpinMessage(channelId, messageId, reason) {
|
||||||
await rest.delete(rest.routes.channels.pin(channelId, messageId), reason ? { reason } : undefined)
|
await rest.delete(rest.routes.channels.pin(channelId, messageId), { reason })
|
||||||
},
|
},
|
||||||
|
|
||||||
async triggerTypingIndicator(channelId) {
|
async triggerTypingIndicator(channelId) {
|
||||||
await rest.post(rest.routes.channels.typing(channelId))
|
await rest.post(rest.routes.channels.typing(channelId))
|
||||||
},
|
},
|
||||||
|
|
||||||
async upsertGlobalApplicationCommands(commands) {
|
async upsertGlobalApplicationCommands(body) {
|
||||||
return await rest.put<DiscordApplicationCommand[]>(rest.routes.interactions.commands.commands(rest.applicationId), commands)
|
return await rest.put<DiscordApplicationCommand[]>(rest.routes.interactions.commands.commands(rest.applicationId), { body })
|
||||||
},
|
},
|
||||||
|
|
||||||
async upsertGuildApplicationCommands(guildId, commands) {
|
async upsertGuildApplicationCommands(guildId, body) {
|
||||||
return await rest.put<DiscordApplicationCommand[]>(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), commands)
|
return await rest.put<DiscordApplicationCommand[]>(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), { body })
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,22 +4,6 @@ import type {
|
|||||||
BeginGuildPrune,
|
BeginGuildPrune,
|
||||||
BigString,
|
BigString,
|
||||||
Camelize,
|
Camelize,
|
||||||
CreateApplicationCommand,
|
|
||||||
CreateAutoModerationRuleOptions,
|
|
||||||
CreateChannelInvite,
|
|
||||||
CreateForumPostWithMessage,
|
|
||||||
CreateGuild,
|
|
||||||
CreateGuildBan,
|
|
||||||
CreateGuildChannel,
|
|
||||||
CreateGuildEmoji,
|
|
||||||
CreateGuildFromTemplate,
|
|
||||||
CreateGuildRole,
|
|
||||||
CreateGuildStickerOptions,
|
|
||||||
CreateMessageOptions,
|
|
||||||
CreateScheduledEvent,
|
|
||||||
CreateStageInstance,
|
|
||||||
CreateTemplate,
|
|
||||||
DeleteWebhookMessageOptions,
|
|
||||||
CamelizedDiscordActiveThreads,
|
CamelizedDiscordActiveThreads,
|
||||||
CamelizedDiscordApplication,
|
CamelizedDiscordApplication,
|
||||||
CamelizedDiscordApplicationCommand,
|
CamelizedDiscordApplicationCommand,
|
||||||
@@ -56,6 +40,22 @@ import type {
|
|||||||
CamelizedDiscordVoiceRegion,
|
CamelizedDiscordVoiceRegion,
|
||||||
CamelizedDiscordWebhook,
|
CamelizedDiscordWebhook,
|
||||||
CamelizedDiscordWelcomeScreen,
|
CamelizedDiscordWelcomeScreen,
|
||||||
|
CreateApplicationCommand,
|
||||||
|
CreateAutoModerationRuleOptions,
|
||||||
|
CreateChannelInvite,
|
||||||
|
CreateForumPostWithMessage,
|
||||||
|
CreateGuild,
|
||||||
|
CreateGuildBan,
|
||||||
|
CreateGuildChannel,
|
||||||
|
CreateGuildEmoji,
|
||||||
|
CreateGuildFromTemplate,
|
||||||
|
CreateGuildRole,
|
||||||
|
CreateGuildStickerOptions,
|
||||||
|
CreateMessageOptions,
|
||||||
|
CreateScheduledEvent,
|
||||||
|
CreateStageInstance,
|
||||||
|
CreateTemplate,
|
||||||
|
DeleteWebhookMessageOptions,
|
||||||
EditAutoModerationRuleOptions,
|
EditAutoModerationRuleOptions,
|
||||||
EditBotMemberOptions,
|
EditBotMemberOptions,
|
||||||
EditChannelPermissionOverridesOptions,
|
EditChannelPermissionOverridesOptions,
|
||||||
@@ -64,9 +64,9 @@ import type {
|
|||||||
EditMessage,
|
EditMessage,
|
||||||
EditOwnVoiceState,
|
EditOwnVoiceState,
|
||||||
EditScheduledEvent,
|
EditScheduledEvent,
|
||||||
EditStageInstanceOptions,
|
|
||||||
EditUserVoiceState,
|
EditUserVoiceState,
|
||||||
ExecuteWebhook,
|
ExecuteWebhook,
|
||||||
|
FileContent,
|
||||||
GetBans,
|
GetBans,
|
||||||
GetGuildAuditLog,
|
GetGuildAuditLog,
|
||||||
GetGuildPruneCountQuery,
|
GetGuildPruneCountQuery,
|
||||||
@@ -92,7 +92,6 @@ import type {
|
|||||||
SearchMembers,
|
SearchMembers,
|
||||||
StartThreadWithMessage,
|
StartThreadWithMessage,
|
||||||
StartThreadWithoutMessage,
|
StartThreadWithoutMessage,
|
||||||
WithReason,
|
|
||||||
} from '@discordeno/types'
|
} from '@discordeno/types'
|
||||||
import type { InvalidRequestBucket } from './invalidBucket.js'
|
import type { InvalidRequestBucket } from './invalidBucket.js'
|
||||||
import type { Queue } from './queue.js'
|
import type { Queue } from './queue.js'
|
||||||
@@ -160,7 +159,7 @@ export interface RestManager {
|
|||||||
/** Reshapes and modifies the obj as needed to make it ready for discords api. */
|
/** Reshapes and modifies the obj as needed to make it ready for discords api. */
|
||||||
changeToDiscordFormat: (obj: any) => any
|
changeToDiscordFormat: (obj: any) => any
|
||||||
/** Creates the request body and headers that are necessary to send a request. Will handle different types of methods and everything necessary for discord. */
|
/** Creates the request body and headers that are necessary to send a request. Will handle different types of methods and everything necessary for discord. */
|
||||||
createRequest: (options: CreateRequestBodyOptions) => RequestBody
|
createRequestBody: (method: RequestMethods, options?: CreateRequestBodyOptions) => RequestBody
|
||||||
/** This will create a infinite loop running in 1 seconds using tail recursion to keep rate limits clean. When a rate limit resets, this will remove it so the queue can proceed. */
|
/** This will create a infinite loop running in 1 seconds using tail recursion to keep rate limits clean. When a rate limit resets, this will remove it so the queue can proceed. */
|
||||||
processRateLimitedPaths: () => void
|
processRateLimitedPaths: () => void
|
||||||
/** Processes the rate limit headers and determines if it needs to be rate limited and returns the bucket id if available */
|
/** Processes the rate limit headers and determines if it needs to be rate limited and returns the bucket id if available */
|
||||||
@@ -170,19 +169,19 @@ export interface RestManager {
|
|||||||
/** Split a url to separate rate limit buckets based on major/minor parameters. */
|
/** Split a url to separate rate limit buckets based on major/minor parameters. */
|
||||||
simplifyUrl: (url: string, method: RequestMethods) => string
|
simplifyUrl: (url: string, method: RequestMethods) => string
|
||||||
/** Make a request to be sent to the api. */
|
/** Make a request to be sent to the api. */
|
||||||
makeRequest: <T = unknown>(method: RequestMethods, url: string, body?: Record<string, any>, options?: Record<string, any>) => Promise<T>
|
makeRequest: <T = unknown>(method: RequestMethods, url: string, options?: Omit<CreateRequestBodyOptions, 'method'>) => Promise<T>
|
||||||
/** Takes a request and processes it into a queue. */
|
/** Takes a request and processes it into a queue. */
|
||||||
processRequest: (request: SendRequestOptions) => void
|
processRequest: (request: SendRequestOptions) => void
|
||||||
/** Make a get request to the api */
|
/** Make a get request to the api */
|
||||||
get: <T = void>(url: string) => Promise<Camelize<T>>
|
get: <T = void>(url: string, options?: Omit<CreateRequestBodyOptions, 'body' | 'method'>) => Promise<Camelize<T>>
|
||||||
/** Make a post request to the api. */
|
/** Make a post request to the api. */
|
||||||
post: <T = void>(url: string, body?: Record<string, any>) => Promise<Camelize<T>>
|
post: <T = void>(url: string, options?: Omit<CreateRequestBodyOptions, 'method'>) => Promise<Camelize<T>>
|
||||||
/** Make a put request to the api. */
|
/** Make a put request to the api. */
|
||||||
put: <T = void>(url: string, body?: Record<string, any>, options?: Record<string, any>) => Promise<Camelize<T>>
|
put: <T = void>(url: string, options?: Omit<CreateRequestBodyOptions, 'method'>) => Promise<Camelize<T>>
|
||||||
/** Make a delete request to the api. */
|
/** Make a delete request to the api. */
|
||||||
delete: (url: string, body?: Record<string, any>) => Promise<void>
|
delete: (url: string, options?: Omit<CreateRequestBodyOptions, 'body' | 'method'>) => Promise<void>
|
||||||
/** Make a patch request to the api. */
|
/** Make a patch request to the api. */
|
||||||
patch: <T = void>(url: string, body?: Record<string, any>) => Promise<Camelize<T>>
|
patch: <T = void>(url: string, options?: Omit<CreateRequestBodyOptions, 'method'>) => Promise<Camelize<T>>
|
||||||
/**
|
/**
|
||||||
* Adds a reaction to a message.
|
* Adds a reaction to a message.
|
||||||
*
|
*
|
||||||
@@ -487,7 +486,7 @@ export interface RestManager {
|
|||||||
*
|
*
|
||||||
* @see {@link https://discord.com/developers/docs/resources/webhook#create-webhook}
|
* @see {@link https://discord.com/developers/docs/resources/webhook#create-webhook}
|
||||||
*/
|
*/
|
||||||
createWebhook: (channelId: BigString, options: CreateWebhook) => Promise<CamelizedDiscordWebhook>
|
createWebhook: (channelId: BigString, options: CreateWebhook, reason?: string) => Promise<CamelizedDiscordWebhook>
|
||||||
/**
|
/**
|
||||||
* Deletes an automod rule.
|
* Deletes an automod rule.
|
||||||
*
|
*
|
||||||
@@ -1187,6 +1186,7 @@ export interface RestManager {
|
|||||||
* Edits a stage instance.
|
* Edits a stage instance.
|
||||||
*
|
*
|
||||||
* @param channelId - The ID of the stage channel the stage instance is associated with.
|
* @param channelId - The ID of the stage channel the stage instance is associated with.
|
||||||
|
* @param topic - Topic of the Stage instance (1-120 characters).
|
||||||
* @returns An instance of the updated {@link CamelizedDiscordStageInstance}.
|
* @returns An instance of the updated {@link CamelizedDiscordStageInstance}.
|
||||||
*
|
*
|
||||||
* @remarks
|
* @remarks
|
||||||
@@ -1196,7 +1196,7 @@ export interface RestManager {
|
|||||||
*
|
*
|
||||||
* @see {@link https://discord.com/developers/docs/resources/stage-instance#modify-stage-instance}
|
* @see {@link https://discord.com/developers/docs/resources/stage-instance#modify-stage-instance}
|
||||||
*/
|
*/
|
||||||
editStageInstance: (channelId: BigString, data: EditStageInstanceOptions) => Promise<CamelizedDiscordStageInstance>
|
editStageInstance: (channelId: BigString, topic: string, reason?: string) => Promise<CamelizedDiscordStageInstance>
|
||||||
/**
|
/**
|
||||||
* Edits the voice state of another user.
|
* Edits the voice state of another user.
|
||||||
*
|
*
|
||||||
@@ -2445,7 +2445,7 @@ export interface RestManager {
|
|||||||
export type RequestMethods = 'GET' | 'POST' | 'DELETE' | 'PATCH' | 'PUT'
|
export type RequestMethods = 'GET' | 'POST' | 'DELETE' | 'PATCH' | 'PUT'
|
||||||
export type ApiVersions = 9 | 10
|
export type ApiVersions = 9 | 10
|
||||||
|
|
||||||
export interface CreateWebhook extends WithReason {
|
export interface CreateWebhook {
|
||||||
/** Name of the webhook (1-80 characters) */
|
/** Name of the webhook (1-80 characters) */
|
||||||
name: string
|
name: string
|
||||||
/** Image url for the default webhook avatar */
|
/** Image url for the default webhook avatar */
|
||||||
@@ -2454,25 +2454,23 @@ export interface CreateWebhook extends WithReason {
|
|||||||
|
|
||||||
export interface CreateRequestBodyOptions {
|
export interface CreateRequestBodyOptions {
|
||||||
headers?: Record<string, string>
|
headers?: Record<string, string>
|
||||||
method: RequestMethods
|
body?: any
|
||||||
body?: Record<string, unknown>
|
|
||||||
unauthorized?: boolean
|
unauthorized?: boolean
|
||||||
url?: string
|
reason?: string
|
||||||
|
files?: FileContent[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RequestBody {
|
export interface RequestBody {
|
||||||
headers: Record<string, string>
|
headers: Record<string, string>
|
||||||
body: string | FormData
|
body?: string | FormData
|
||||||
method: RequestMethods
|
method: RequestMethods
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendRequestOptions {
|
export interface SendRequestOptions {
|
||||||
/** The url to send the request to. */
|
/** The url to send the request to. */
|
||||||
url: string
|
url: string
|
||||||
/** The method to use when sending the request. */
|
/** The method to use for sending the request. */
|
||||||
method: RequestMethods
|
method: RequestMethods
|
||||||
/** The body to be sent in the request. */
|
|
||||||
body?: Record<string, any>
|
|
||||||
/** The amount of times this request has been retried. */
|
/** The amount of times this request has been retried. */
|
||||||
retryCount: number
|
retryCount: number
|
||||||
/** Handler to retry a request should it be rate limited. */
|
/** Handler to retry a request should it be rate limited. */
|
||||||
@@ -2484,7 +2482,7 @@ export interface SendRequestOptions {
|
|||||||
/** If this request has a bucket id which it falls under for rate limit */
|
/** If this request has a bucket id which it falls under for rate limit */
|
||||||
bucketId?: string
|
bucketId?: string
|
||||||
/** Additional request options, used for things like overriding authorization header. */
|
/** Additional request options, used for things like overriding authorization header. */
|
||||||
options?: Record<string, any>
|
requestBodyOptions?: CreateRequestBodyOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RestRateLimitedPath {
|
export interface RestRateLimitedPath {
|
||||||
@@ -2508,9 +2506,12 @@ export interface WebhookMessageEditor {
|
|||||||
*
|
*
|
||||||
* @see {@link https://discord.com/developers/docs/resources/webhook#edit-webhook-message}
|
* @see {@link https://discord.com/developers/docs/resources/webhook#edit-webhook-message}
|
||||||
*/
|
*/
|
||||||
(webhookId: BigString, token: string, messageId: BigString, options: InteractionCallbackData & { threadId?: BigString }): Promise<
|
(
|
||||||
CamelizedDiscordMessage
|
webhookId: BigString,
|
||||||
>
|
token: string,
|
||||||
|
messageId: BigString,
|
||||||
|
options: InteractionCallbackData & { threadId?: BigString },
|
||||||
|
): Promise<CamelizedDiscordMessage>
|
||||||
/**
|
/**
|
||||||
* Edits the original webhook message.
|
* Edits the original webhook message.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ describe('Member tests', () => {
|
|||||||
|
|
||||||
it('Send a direct message', async () => {
|
it('Send a direct message', async () => {
|
||||||
// DM test only on dd unit testing bot
|
// DM test only on dd unit testing bot
|
||||||
if (rest.applicationId.toString() !== "770381961553510451") return;
|
if (rest.applicationId.toString() !== '770381961553510451') return
|
||||||
// Itoh Alt ID
|
// Itoh Alt ID
|
||||||
const channel = await rest.getDmChannel(750661528360845322n)
|
const channel = await rest.getDmChannel(750661528360845322n)
|
||||||
expect(channel?.id).to.exist
|
expect(channel?.id).to.exist
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ after(async () => {
|
|||||||
|
|
||||||
describe('Send a message', () => {
|
describe('Send a message', () => {
|
||||||
it('With content', async () => {
|
it('With content', async () => {
|
||||||
const message = await rest.sendMessage('1041029705790402611', { content: 'testing rate limit manager' })
|
const message = await rest.sendMessage(e2ecache.channel.id, { content: 'testing rate limit manager' })
|
||||||
expect(message.content).to.be.equal('testing rate limit manager')
|
expect(message.content).to.be.equal('testing rate limit manager')
|
||||||
|
|
||||||
const edited = await rest.editMessage(message.channelId, message.id, { content: 'testing rate limit manager edited' })
|
const edited = await rest.editMessage(message.channelId, message.id, { content: 'testing rate limit manager edited' })
|
||||||
@@ -37,7 +37,7 @@ describe('Send a message', () => {
|
|||||||
expect(image).to.not.be.undefined
|
expect(image).to.not.be.undefined
|
||||||
if (!image) throw new Error('Was not able to fetch the image.')
|
if (!image) throw new Error('Was not able to fetch the image.')
|
||||||
|
|
||||||
const message = await rest.sendMessage('1041029705790402611', { file: { blob: image, name: 'gamer' } })
|
const message = await rest.sendMessage(e2ecache.channel.id, { files: [{ blob: image, name: 'gamer' }] })
|
||||||
expect(message.attachments.length).to.be.greaterThan(0)
|
expect(message.attachments.length).to.be.greaterThan(0)
|
||||||
const [attachment] = message.attachments
|
const [attachment] = message.attachments
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,12 @@ export const rest = createRestManager({
|
|||||||
})
|
})
|
||||||
rest.deleteQueueDelay = 10000
|
rest.deleteQueueDelay = 10000
|
||||||
|
|
||||||
|
const guild = await rest.createGuild({ name: 'ddenotester' });
|
||||||
|
const channel = await rest.createChannel(guild.id, { name: "ddenotestchannel" });
|
||||||
|
|
||||||
export const e2ecache = {
|
export const e2ecache = {
|
||||||
guild: await rest.createGuild({ name: 'ddenotester' }),
|
guild,
|
||||||
|
channel,
|
||||||
deletedGuild: false,
|
deletedGuild: false,
|
||||||
communityGuildId: E2E_TEST_GUILD_ID,
|
communityGuildId: E2E_TEST_GUILD_ID,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ describe('[rest] manager', () => {
|
|||||||
version: 9,
|
version: 9,
|
||||||
proxy: {
|
proxy: {
|
||||||
baseUrl: 'https://localhost:8000',
|
baseUrl: 'https://localhost:8000',
|
||||||
authorization: token
|
authorization: token,
|
||||||
}
|
},
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
const rest = createRestManager(options)
|
const rest = createRestManager(options)
|
||||||
@@ -80,7 +80,7 @@ describe('[rest] manager', () => {
|
|||||||
it('Will add method in front route if method is DELETE', () => {
|
it('Will add method in front route if method is DELETE', () => {
|
||||||
const rest = createRestManager({ token })
|
const rest = createRestManager({ token })
|
||||||
expect(rest.simplifyUrl('/channels/555555555555555555/messages/555555555555555555', 'DELETE')).to.be.equal(
|
expect(rest.simplifyUrl('/channels/555555555555555555/messages/555555555555555555', 'DELETE')).to.be.equal(
|
||||||
'DELETE/channels/555555555555555555/messages/x',
|
'D/channels/555555555555555555/messages/x',
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -149,6 +149,6 @@ and unofficial templates:
|
|||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
- [Website](https://discordeno.github.io/discordeno/)
|
- [Website](https://discordeno.js.org/)
|
||||||
- [Documentation](https://doc.deno.land/https/deno.land/x/discordeno/mod.ts)
|
- [Documentation](https://doc.deno.land/https/deno.land/x/discordeno/mod.ts)
|
||||||
- [Discord](https://discord.com/invite/5vBgXk3UcZ)
|
- [Discord](https://discord.com/invite/5vBgXk3UcZ)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import type { FileContent } from './discordeno.js'
|
|
||||||
import type {
|
import type {
|
||||||
ActivityTypes,
|
ActivityTypes,
|
||||||
AllowedMentionsTypes,
|
AllowedMentionsTypes,
|
||||||
@@ -2564,8 +2563,6 @@ export interface DiscordCreateForumPostWithMessage {
|
|||||||
components?: DiscordMessageComponents[]
|
components?: DiscordMessageComponents[]
|
||||||
/** IDs of up to 3 stickers in the server to send in the message */
|
/** IDs of up to 3 stickers in the server to send in the message */
|
||||||
sticker_ids?: string[]
|
sticker_ids?: string[]
|
||||||
/** Contents of the file being sent. See {@link https://discord.com/developers/docs/reference#uploading-files Uploading Files} */
|
|
||||||
file: FileContent | FileContent[] | undefined
|
|
||||||
/** JSON-encoded body of non-file params, only for multipart/form-data requests. See {@link https://discord.com/developers/docs/reference#uploading-files Uploading Files} */
|
/** JSON-encoded body of non-file params, only for multipart/form-data requests. See {@link https://discord.com/developers/docs/reference#uploading-files Uploading Files} */
|
||||||
payload_json?: string
|
payload_json?: string
|
||||||
/** Attachment objects with filename and description. See {@link https://discord.com/developers/docs/reference#uploading-files Uploading Files} */
|
/** Attachment objects with filename and description. See {@link https://discord.com/developers/docs/reference#uploading-files Uploading Files} */
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ export interface CreateMessageOptions {
|
|||||||
/** When sending, whether to error if the referenced message doesn't exist instead of sending as a normal (non-reply) message, default true */
|
/** When sending, whether to error if the referenced message doesn't exist instead of sending as a normal (non-reply) message, default true */
|
||||||
failIfNotExists: boolean
|
failIfNotExists: boolean
|
||||||
}
|
}
|
||||||
/** The contents of the file being sent */
|
/** The contents of the files being sent */
|
||||||
file?: FileContent | FileContent[]
|
files?: FileContent[]
|
||||||
/** The components you would like to have sent in this message */
|
/** The components you would like to have sent in this message */
|
||||||
components?: MessageComponents
|
components?: MessageComponents
|
||||||
/** IDs of up to 3 stickers in the server to send in the message */
|
/** IDs of up to 3 stickers in the server to send in the message */
|
||||||
@@ -431,8 +431,8 @@ export interface InteractionCallbackData {
|
|||||||
embeds?: Array<Camelize<DiscordEmbed>>
|
embeds?: Array<Camelize<DiscordEmbed>>
|
||||||
/** Allowed mentions for the message */
|
/** Allowed mentions for the message */
|
||||||
allowedMentions?: AllowedMentions
|
allowedMentions?: AllowedMentions
|
||||||
/** The contents of the file being sent */
|
/** The contents of the files being sent */
|
||||||
file?: FileContent | FileContent[]
|
files?: FileContent[]
|
||||||
/** The customId you want to use for this modal response. */
|
/** The customId you want to use for this modal response. */
|
||||||
customId?: string
|
customId?: string
|
||||||
/** The title you want to use for this modal response. */
|
/** The title you want to use for this modal response. */
|
||||||
@@ -673,8 +673,8 @@ export interface ExecuteWebhook {
|
|||||||
avatarUrl?: string
|
avatarUrl?: string
|
||||||
/** True if this is a TTS message */
|
/** True if this is a TTS message */
|
||||||
tts?: boolean
|
tts?: boolean
|
||||||
/** The contents of the file being sent */
|
/** The contents of the files being sent */
|
||||||
file?: FileContent | FileContent[]
|
files?: FileContent[]
|
||||||
/** Embedded `rich` content */
|
/** Embedded `rich` content */
|
||||||
embeds?: Array<Camelize<DiscordEmbed>>
|
embeds?: Array<Camelize<DiscordEmbed>>
|
||||||
/** Allowed mentions for the message */
|
/** Allowed mentions for the message */
|
||||||
@@ -706,8 +706,8 @@ export interface CreateForumPostWithMessage extends WithReason {
|
|||||||
embeds?: Array<Camelize<DiscordEmbed>>
|
embeds?: Array<Camelize<DiscordEmbed>>
|
||||||
/** Allowed mentions for the message */
|
/** Allowed mentions for the message */
|
||||||
allowedMentions?: AllowedMentions
|
allowedMentions?: AllowedMentions
|
||||||
/** The contents of the file being sent */
|
/** The contents of the files being sent */
|
||||||
file?: FileContent | FileContent[]
|
files?: FileContent[]
|
||||||
/** The components you would like to have sent in this message */
|
/** The components you would like to have sent in this message */
|
||||||
components?: MessageComponents
|
components?: MessageComponents
|
||||||
}
|
}
|
||||||
@@ -890,8 +890,8 @@ export interface EditMessage {
|
|||||||
embeds?: Array<Camelize<DiscordEmbed>> | null
|
embeds?: Array<Camelize<DiscordEmbed>> | null
|
||||||
/** Edit the flags of the message (only `SUPPRESS_EMBEDS` can currently be set/unset) */
|
/** Edit the flags of the message (only `SUPPRESS_EMBEDS` can currently be set/unset) */
|
||||||
flags?: 4 | null
|
flags?: 4 | null
|
||||||
/** The contents of the file being sent/edited */
|
/** The contents of the files being sent/edited */
|
||||||
file?: FileContent | FileContent[] | null
|
files?: FileContent[] | null
|
||||||
/** Allowed mentions for the message */
|
/** Allowed mentions for the message */
|
||||||
allowedMentions?: AllowedMentions
|
allowedMentions?: AllowedMentions
|
||||||
/** When specified (adding new attachments), attachments which are not provided in this list will be removed. */
|
/** When specified (adding new attachments), attachments which are not provided in this list will be removed. */
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ export enum TeamMembershipStates {
|
|||||||
|
|
||||||
/** https://discord.com/developers/docs/topics/oauth2#application-application-flags */
|
/** https://discord.com/developers/docs/topics/oauth2#application-application-flags */
|
||||||
export enum ApplicationFlags {
|
export enum ApplicationFlags {
|
||||||
|
/** Indicates if an app uses the Auto Moderation API. */
|
||||||
|
ApplicationAutoModerationRuleCreateBadge = 1 << 6,
|
||||||
/** Intent required for bots in **100 or more servers** to receive [`presence_update` events](#DOCS_TOPICS_GATEWAY/presence-update) */
|
/** Intent required for bots in **100 or more servers** to receive [`presence_update` events](#DOCS_TOPICS_GATEWAY/presence-update) */
|
||||||
GatewayPresence = 1 << 12,
|
GatewayPresence = 1 << 12,
|
||||||
/** Intent required for bots in under 100 servers to receive [`presence_update` events](#DOCS_TOPICS_GATEWAY/presence-update), found in Bot Settings */
|
/** Intent required for bots in under 100 servers to receive [`presence_update` events](#DOCS_TOPICS_GATEWAY/presence-update), found in Bot Settings */
|
||||||
|
|||||||
@@ -149,6 +149,6 @@ and unofficial templates:
|
|||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
- [Website](https://discordeno.github.io/discordeno/)
|
- [Website](https://discordeno.js.org/)
|
||||||
- [Documentation](https://doc.deno.land/https/deno.land/x/discordeno/mod.ts)
|
- [Documentation](https://doc.deno.land/https/deno.land/x/discordeno/mod.ts)
|
||||||
- [Discord](https://discord.com/invite/5vBgXk3UcZ)
|
- [Discord](https://discord.com/invite/5vBgXk3UcZ)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user