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:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
merge_group:
|
||||
|
||||
jobs:
|
||||
build-type-and-test:
|
||||
@@ -30,7 +33,7 @@ jobs:
|
||||
path: .turbo
|
||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
||||
- name: Build Type and Test
|
||||
run: yarn build:type --cache-dir=".turbo" --filter=./packages/gateway
|
||||
run: yarn build:type --cache-dir=".turbo"
|
||||
|
||||
build-dist:
|
||||
name: Build Dist
|
||||
@@ -57,7 +60,7 @@ jobs:
|
||||
path: .turbo
|
||||
key: ${{ runner.os }}-turbo-build-${{ github.sha }}
|
||||
- name: Type Test
|
||||
run: yarn build --cache-dir=".turbo" --filter=./packages/gateway
|
||||
run: yarn build --cache-dir=".turbo"
|
||||
|
||||
format-unit-and-integration-test:
|
||||
name: Format Test
|
||||
@@ -91,7 +94,7 @@ jobs:
|
||||
path: .turbo
|
||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
||||
- name: Check Formatting
|
||||
run: yarn lint --cache-dir=".turbo" --filter=./packages/gateway
|
||||
run: yarn lint --cache-dir=".turbo"
|
||||
|
||||
test-type-unit-and-integration-test:
|
||||
name: Test Type Test
|
||||
@@ -125,9 +128,56 @@ jobs:
|
||||
path: .turbo
|
||||
key: ${{ runner.os }}-turbo-build:type-${{ github.sha }}
|
||||
- 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
|
||||
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:
|
||||
name: Gateway
|
||||
needs: build-dist
|
||||
@@ -146,3 +196,50 @@ jobs:
|
||||
uses: ./.github/workflows/other-runtime-unit-test.yml
|
||||
with:
|
||||
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:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
package: ["gateway", "rest", "types", "utils", "bot", "client"]
|
||||
package: ["gateway", "rest", "types", "utils", "bot"]
|
||||
steps:
|
||||
- uses: actions/checkout@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
|
||||
.docusaurus
|
||||
.cache-loader
|
||||
/db
|
||||
|
||||
# misc
|
||||
.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://codecov.io/gh/discordeno/discordeno)
|
||||

|
||||
|
||||
## 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.
|
||||
|
||||
## Packages
|
||||
|
||||
| Package | npm | Tests | Coverage |
|
||||
| ------------------------------------------------------------------------ | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [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/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/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) |
|
||||
| Package | npm | Tests |
|
||||
| ------------------------------------------------------------------------ | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [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/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/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) |
|
||||
|
||||
## 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.
|
||||
- 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 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.
|
||||
- **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.
|
||||
@@ -93,11 +93,69 @@ Have your cache setup in any way you like. Redis, PGSQL or any cache layer you w
|
||||
|
||||
## 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
|
||||
|
||||
- [Website](https://discordeno.github.io/discordeno/)
|
||||
- [Website](https://discordeno.js.org/)
|
||||
- [Discord](https://discord.com/invite/5vBgXk3UcZ)
|
||||
|
||||
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:
|
||||
client:
|
||||
carryforward: false
|
||||
client-unit:
|
||||
carryforward: false
|
||||
|
||||
discordeno:
|
||||
carryforward: false
|
||||
discordeno-unit:
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
"@discordeno/types": "./packages/types/dist/index.js",
|
||||
"@discordeno/rest": "./packages/rest/dist/index.js",
|
||||
"@discordeno/gateway": "./packages/gateway/dist/index.js",
|
||||
"@discordeno/bot": "./packages/bot/dist/index.js",
|
||||
"@discordeno/client": "./packages/client/dist/index.js"
|
||||
"@discordeno/bot": "./packages/bot/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
|
||||
[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)
|
||||
|
||||
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[]
|
||||
/** Allowed mentions for the message */
|
||||
allowedMentions?: AllowedMentions
|
||||
/** The contents of the file being sent */
|
||||
file?: FileContent | FileContent[]
|
||||
/** The contents of the files being sent */
|
||||
files?: FileContent[]
|
||||
/** The customId you want to use for this modal response. */
|
||||
customId?: string
|
||||
/** 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,
|
||||
delay,
|
||||
encode,
|
||||
findFiles,
|
||||
getBotIdFromToken,
|
||||
isGetMessagesAfter,
|
||||
isGetMessagesAround,
|
||||
@@ -33,7 +32,6 @@ import type {
|
||||
DiscordBan,
|
||||
DiscordChannel,
|
||||
DiscordEmoji,
|
||||
DiscordFollowAnnouncementChannel,
|
||||
DiscordFollowedChannel,
|
||||
DiscordGetGatewayBot,
|
||||
DiscordGuild,
|
||||
@@ -67,7 +65,7 @@ import type {
|
||||
MfaLevels,
|
||||
ModifyGuildTemplate,
|
||||
} 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
|
||||
const version = '19.0.0-alpha.1'
|
||||
@@ -693,62 +691,54 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
||||
return obj
|
||||
},
|
||||
|
||||
createRequest(options) {
|
||||
createRequestBody(method, options) {
|
||||
const headers: Record<string, string> = {
|
||||
'user-agent': `DiscordBot (https://github.com/discordeno/discordeno, v${version})`,
|
||||
}
|
||||
|
||||
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 (!options?.unauthorized) headers.authorization = `Bot ${rest.token}`
|
||||
|
||||
// IF A REASON IS PROVIDED ENCODE IT IN HEADERS
|
||||
if (options.body?.reason) {
|
||||
headers['X-Audit-Log-Reason'] = encodeURIComponent(options.body.reason as string)
|
||||
options.body.reason = undefined
|
||||
if (options?.reason !== undefined) {
|
||||
headers['x-audit-log-reason'] = encodeURIComponent(options?.reason)
|
||||
}
|
||||
|
||||
if (options.body) {
|
||||
const { file } = options.body
|
||||
if (file) {
|
||||
const files = findFiles(file)
|
||||
const form = new FormData()
|
||||
let body: string | FormData | undefined
|
||||
|
||||
// WHEN CREATING A STICKER, DISCORD WANTS FORM DATA ONLY
|
||||
if (options.url?.endsWith('/stickers') && options.method === 'POST') {
|
||||
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)
|
||||
}
|
||||
// TODO: check if we need to add specific check for GET method
|
||||
// Since GET does not allow bodies
|
||||
|
||||
if (file) options.body.file = undefined
|
||||
form.append('payload_json', JSON.stringify(rest.changeToDiscordFormat(options.body)))
|
||||
}
|
||||
|
||||
options.body.file = form
|
||||
} else if (options.body && !['GET', 'DELETE'].includes(options.method)) {
|
||||
headers['Content-Type'] = 'application/json'
|
||||
// Have to check for attachments first, since body then has to be send in a different way.
|
||||
if (options?.files !== undefined) {
|
||||
const form = new FormData()
|
||||
for (let i = 0; i < options.files.length; ++i) {
|
||||
form.append(`file${i}`, options.files[i].blob, options.files[i].name)
|
||||
}
|
||||
|
||||
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 {
|
||||
body,
|
||||
headers,
|
||||
body: (options.body?.file ?? JSON.stringify(rest.changeToDiscordFormat(options.body))) as FormData | string,
|
||||
method: options.method,
|
||||
method,
|
||||
}
|
||||
},
|
||||
|
||||
@@ -860,7 +850,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
||||
|
||||
async sendRequest(options) {
|
||||
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' } })
|
||||
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) })
|
||||
},
|
||||
|
||||
// Credits: github.com/abalabahaha/eris lib/rest/RequestHandler.js#L397
|
||||
// Modified for our use-case
|
||||
simplifyUrl(url, method) {
|
||||
let route = url
|
||||
.replace(/\/([a-z-]+)\/(?:[0-9]{17,19})/g, function (match, p: string) {
|
||||
return ['channels', 'guilds'].includes(p) ? match : `/${p}/x`
|
||||
})
|
||||
.replace(/\/reactions\/[^/]+/g, '/reactions/x')
|
||||
const parts = url.split('/')
|
||||
const secondLastPart = parts[parts.length - 2]
|
||||
|
||||
// GENERAL /reactions and /reactions/emoji/@me share the buckets
|
||||
if (route.includes('/reactions')) {
|
||||
route = route.substring(0, route.indexOf('/reactions') + '/reactions'.length)
|
||||
if (secondLastPart === 'channels' || secondLastPart === 'guilds') {
|
||||
return url
|
||||
}
|
||||
|
||||
// Delete Message endpoint has its own rate limit
|
||||
if (method === 'DELETE' && route.endsWith('/messages/x')) {
|
||||
route = method + route
|
||||
if (secondLastPart === 'reactions' || parts[parts.length - 1] === '@me') {
|
||||
parts.splice(-2)
|
||||
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) {
|
||||
@@ -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] === '/') {
|
||||
// Special handling for sending blobs across http to proxy
|
||||
if (body?.file) {
|
||||
if (!Array.isArray(body.file)) {
|
||||
body.file = [body.file]
|
||||
// TODO: fix this hacky handling
|
||||
if (!(options?.body instanceof FormData) && !Array.isArray(options?.body) && options?.body?.file) {
|
||||
if (!Array.isArray(options.body.file)) {
|
||||
options.body.file = [options.body.file]
|
||||
}
|
||||
// convert blobs to string before sending to proxy
|
||||
body.file = await Promise.all(
|
||||
body.file.map(async (f: FileContent) => {
|
||||
options.body.file = await Promise.all(
|
||||
(options.body.file as FileContent[]).map(async (f: FileContent) => {
|
||||
const url = encode(await f.blob.arrayBuffer())
|
||||
|
||||
return { name: f.name, blob: `data:${f.blob.type};base64,${url}` }
|
||||
@@ -977,17 +973,18 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
||||
const headers: HeadersInit = {
|
||||
Authorization: rest.authorization ?? '',
|
||||
}
|
||||
if (body) {
|
||||
if (options?.body) {
|
||||
headers['Content-Type'] = 'application/json'
|
||||
}
|
||||
|
||||
const result = await fetch(`${rest.baseUrl}${url}`, {
|
||||
body: body ? JSON.stringify(body) : undefined,
|
||||
body: options?.body ? JSON.stringify(options.body) : undefined,
|
||||
headers,
|
||||
method,
|
||||
})
|
||||
|
||||
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
|
||||
if (!err?.body) throw new Error(`Error: ${err.message ?? result.statusText}`)
|
||||
throw new Error(JSON.stringify(err))
|
||||
@@ -1000,40 +997,39 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
||||
const payload: SendRequestOptions = {
|
||||
url,
|
||||
method,
|
||||
body,
|
||||
requestBodyOptions: options,
|
||||
retryCount: 0,
|
||||
retryRequest: async function (options: SendRequestOptions) {
|
||||
retryRequest: async function(payload: SendRequestOptions) {
|
||||
rest.processRequest(payload)
|
||||
},
|
||||
resolve: (data) => {
|
||||
resolve(data.status !== 204 ? JSON.parse(data.body ?? '{}') : undefined)
|
||||
},
|
||||
reject,
|
||||
options,
|
||||
}
|
||||
|
||||
rest.processRequest(payload)
|
||||
})
|
||||
},
|
||||
|
||||
async get<T = Record<string, unknown>>(url: string) {
|
||||
return camelize(await rest.makeRequest('GET', url)) as Camelize<T>
|
||||
async get<T = Record<string, unknown>>(url: string, options?: Omit<CreateRequestBodyOptions, 'body' | 'method'>) {
|
||||
return camelize(await rest.makeRequest('GET', url, options)) as Camelize<T>
|
||||
},
|
||||
|
||||
async post<T = Record<string, unknown>>(url: string, body?: Record<string, any>) {
|
||||
return camelize(await rest.makeRequest('POST', url, body)) as Camelize<T>
|
||||
async post<T = Record<string, unknown>>(url: string, options?: Omit<CreateRequestBodyOptions, 'body' | 'method'>) {
|
||||
return camelize(await rest.makeRequest('POST', url, options)) as Camelize<T>
|
||||
},
|
||||
|
||||
async delete(url: string, body?: Record<string, any>) {
|
||||
camelize(await rest.makeRequest('DELETE', url, body))
|
||||
async delete(url: string, options?: Omit<CreateRequestBodyOptions, 'body' | 'method'>) {
|
||||
camelize(await rest.makeRequest('DELETE', url, options))
|
||||
},
|
||||
|
||||
async patch<T = Record<string, unknown>>(url: string, body?: Record<string, any>) {
|
||||
return camelize(await rest.makeRequest('PATCH', url, body)) as Camelize<T>
|
||||
async patch<T = Record<string, unknown>>(url: string, options?: Omit<CreateRequestBodyOptions, 'body' | 'method'>) {
|
||||
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>) {
|
||||
return camelize(await rest.makeRequest('PUT', url, body, options)) as Camelize<T>
|
||||
async put<T = void>(url: string, options?: Omit<CreateRequestBodyOptions, 'body' | 'method'>) {
|
||||
return camelize(await rest.makeRequest('PUT', url, options)) as Camelize<T>
|
||||
},
|
||||
|
||||
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))
|
||||
},
|
||||
|
||||
async createAutomodRule(guildId, options) {
|
||||
return await rest.post<DiscordAutoModerationRule>(rest.routes.guilds.automod.rules(guildId), options)
|
||||
async createAutomodRule(guildId, body) {
|
||||
return await rest.post<DiscordAutoModerationRule>(rest.routes.guilds.automod.rules(guildId), { body })
|
||||
},
|
||||
|
||||
async createChannel(guildId, options) {
|
||||
return await rest.post<DiscordChannel>(rest.routes.guilds.channels(guildId), options)
|
||||
async createChannel(guildId, body) {
|
||||
return await rest.post<DiscordChannel>(rest.routes.guilds.channels(guildId), { body })
|
||||
},
|
||||
|
||||
async createEmoji(guildId, options) {
|
||||
return await rest.post<DiscordEmoji>(rest.routes.guilds.emojis(guildId), options)
|
||||
async createEmoji(guildId, body) {
|
||||
return await rest.post<DiscordEmoji>(rest.routes.guilds.emojis(guildId), { body })
|
||||
},
|
||||
|
||||
async createGlobalApplicationCommand(command) {
|
||||
return await rest.post<DiscordApplicationCommand>(rest.routes.interactions.commands.commands(rest.applicationId), command)
|
||||
async createGlobalApplicationCommand(body) {
|
||||
return await rest.post<DiscordApplicationCommand>(rest.routes.interactions.commands.commands(rest.applicationId), { body })
|
||||
},
|
||||
|
||||
async createGuild(options) {
|
||||
return await rest.post<DiscordGuild>(rest.routes.guilds.all(), options)
|
||||
async createGuild(body) {
|
||||
return await rest.post<DiscordGuild>(rest.routes.guilds.all(), { body })
|
||||
},
|
||||
|
||||
async createGuildApplicationCommand(command, guildId) {
|
||||
return await rest.post<DiscordApplicationCommand>(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), command)
|
||||
async createGuildApplicationCommand(body, guildId) {
|
||||
return await rest.post<DiscordApplicationCommand>(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), { body })
|
||||
},
|
||||
|
||||
async createGuildFromTemplate(templateCode, options) {
|
||||
if (options.icon) {
|
||||
options.icon = await urlToBase64(options.icon)
|
||||
async createGuildFromTemplate(templateCode, body) {
|
||||
if (body.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) {
|
||||
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) {
|
||||
return await rest.post<DiscordTemplate>(rest.routes.guilds.templates.all(guildId), options)
|
||||
async createGuildTemplate(guildId, body) {
|
||||
return await rest.post<DiscordTemplate>(rest.routes.guilds.templates.all(guildId), { body })
|
||||
},
|
||||
|
||||
async createForumThread(channelId, options) {
|
||||
return await rest.post<DiscordChannel>(rest.routes.channels.forum(channelId), options)
|
||||
async createForumThread(channelId, body) {
|
||||
return await rest.post<DiscordChannel>(rest.routes.channels.forum(channelId), { body, files: body.files })
|
||||
},
|
||||
|
||||
async createInvite(channelId, options = {}) {
|
||||
return await rest.post<DiscordInvite>(rest.routes.channels.invites(channelId), options)
|
||||
async createInvite(channelId, body = {}) {
|
||||
return await rest.post<DiscordInvite>(rest.routes.channels.invites(channelId), { body })
|
||||
},
|
||||
|
||||
async createRole(guildId, options, reason) {
|
||||
return await rest.post<DiscordRole>(rest.routes.guilds.roles.all(guildId), {
|
||||
...options,
|
||||
reason,
|
||||
})
|
||||
async createRole(guildId, body, reason) {
|
||||
return await rest.post<DiscordRole>(rest.routes.guilds.roles.all(guildId), { body, reason })
|
||||
},
|
||||
|
||||
async createScheduledEvent(guildId, options) {
|
||||
return await rest.post<DiscordScheduledEvent>(rest.routes.guilds.events.events(guildId), options)
|
||||
async createScheduledEvent(guildId, body) {
|
||||
return await rest.post<DiscordScheduledEvent>(rest.routes.guilds.events.events(guildId), { body })
|
||||
},
|
||||
|
||||
async createStageInstance(options) {
|
||||
return await rest.post<DiscordStageInstance>(rest.routes.channels.stages(), options)
|
||||
async createStageInstance(body) {
|
||||
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), {
|
||||
name: options.name,
|
||||
avatar: options.avatar ? await urlToBase64(options.avatar) : undefined,
|
||||
reason: options.reason,
|
||||
body: {
|
||||
name: options.name,
|
||||
avatar: options.avatar ? await urlToBase64(options.avatar) : undefined,
|
||||
},
|
||||
reason,
|
||||
})
|
||||
},
|
||||
|
||||
@@ -1147,7 +1148,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
||||
},
|
||||
|
||||
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) {
|
||||
@@ -1171,7 +1172,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
||||
},
|
||||
|
||||
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) {
|
||||
@@ -1183,7 +1184,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
||||
},
|
||||
|
||||
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) {
|
||||
@@ -1192,7 +1193,9 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
||||
|
||||
async deleteMessages(channelId, messageIds, reason) {
|
||||
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,
|
||||
})
|
||||
},
|
||||
@@ -1226,7 +1229,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
||||
},
|
||||
|
||||
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) {
|
||||
@@ -1247,155 +1250,167 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
||||
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>(
|
||||
rest.routes.interactions.commands.permission(rest.applicationId, guildId, commandId),
|
||||
{
|
||||
permissions: options,
|
||||
},
|
||||
{
|
||||
body: {
|
||||
permissions,
|
||||
},
|
||||
headers: { authorization: `Bearer ${bearerToken}` },
|
||||
},
|
||||
)
|
||||
},
|
||||
|
||||
async editAutomodRule(guildId, ruleId, options) {
|
||||
return await rest.patch<DiscordAutoModerationRule>(rest.routes.guilds.automod.rule(guildId, ruleId), options)
|
||||
async editAutomodRule(guildId, ruleId, body) {
|
||||
return await rest.patch<DiscordAutoModerationRule>(rest.routes.guilds.automod.rule(guildId, ruleId), { body })
|
||||
},
|
||||
|
||||
async editBotProfile(options) {
|
||||
const avatar = options?.botAvatarURL ? await urlToBase64(options?.botAvatarURL) : options?.botAvatarURL
|
||||
|
||||
return await rest.patch<DiscordUser>(rest.routes.userBot(), {
|
||||
username: options.username?.trim(),
|
||||
avatar,
|
||||
body: {
|
||||
username: options.username?.trim(),
|
||||
avatar,
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
async editChannel(channelId, options) {
|
||||
return await rest.patch<DiscordChannel>(rest.routes.channels.channel(channelId), options)
|
||||
async editChannel(channelId, body) {
|
||||
return await rest.patch<DiscordChannel>(rest.routes.channels.channel(channelId), { body })
|
||||
},
|
||||
|
||||
async editChannelPermissionOverrides(channelId, options) {
|
||||
await rest.put(rest.routes.channels.overwrite(channelId, options.id), options)
|
||||
async editChannelPermissionOverrides(channelId, body) {
|
||||
await rest.put(rest.routes.channels.overwrite(channelId, body.id), { body })
|
||||
},
|
||||
|
||||
async editChannelPositions(guildId, channelPositions) {
|
||||
await rest.patch(rest.routes.guilds.channels(guildId), channelPositions)
|
||||
async editChannelPositions(guildId, body) {
|
||||
await rest.patch(rest.routes.guilds.channels(guildId), { body })
|
||||
},
|
||||
|
||||
async editEmoji(guildId, id, options) {
|
||||
return await rest.patch<DiscordEmoji>(rest.routes.guilds.emoji(guildId, id), options)
|
||||
async editEmoji(guildId, id, body) {
|
||||
return await rest.patch<DiscordEmoji>(rest.routes.guilds.emoji(guildId, id), { body })
|
||||
},
|
||||
|
||||
async editFollowupMessage(token, messageId, options) {
|
||||
return await rest.patch<DiscordMessage>(rest.routes.interactions.responses.message(rest.applicationId, token, messageId), options)
|
||||
async editFollowupMessage(token, messageId, body) {
|
||||
return await rest.patch<DiscordMessage>(rest.routes.interactions.responses.message(rest.applicationId, token, messageId), {
|
||||
body,
|
||||
files: body.files,
|
||||
})
|
||||
},
|
||||
|
||||
async editGlobalApplicationCommand(commandId, options) {
|
||||
return await rest.patch<DiscordApplicationCommand>(rest.routes.interactions.commands.command(rest.applicationId, commandId), options)
|
||||
async editGlobalApplicationCommand(commandId, body) {
|
||||
return await rest.patch<DiscordApplicationCommand>(rest.routes.interactions.commands.command(rest.applicationId, commandId), { body })
|
||||
},
|
||||
|
||||
async editGuild(guildId, options) {
|
||||
return await rest.patch<DiscordGuild>(rest.routes.guilds.guild(guildId), options)
|
||||
async editGuild(guildId, body) {
|
||||
return await rest.patch<DiscordGuild>(rest.routes.guilds.guild(guildId), { body })
|
||||
},
|
||||
|
||||
async editGuildApplicationCommand(commandId, guildId, options) {
|
||||
return await rest.patch<DiscordApplicationCommand>(
|
||||
rest.routes.interactions.commands.guilds.one(rest.applicationId, guildId, commandId),
|
||||
options,
|
||||
)
|
||||
async editGuildApplicationCommand(commandId, guildId, body) {
|
||||
return await rest.patch<DiscordApplicationCommand>(rest.routes.interactions.commands.guilds.one(rest.applicationId, guildId, commandId), {
|
||||
body,
|
||||
})
|
||||
},
|
||||
|
||||
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) {
|
||||
return await rest.patch<DiscordSticker>(rest.routes.guilds.sticker(guildId, stickerId), options)
|
||||
async editGuildSticker(guildId, stickerId, body) {
|
||||
return await rest.patch<DiscordSticker>(rest.routes.guilds.sticker(guildId, stickerId), { body })
|
||||
},
|
||||
|
||||
async editGuildTemplate(guildId, templateCode: string, options: ModifyGuildTemplate): Promise<Camelize<DiscordTemplate>> {
|
||||
return await rest.patch<DiscordTemplate>(rest.routes.guilds.templates.guild(guildId, templateCode), options)
|
||||
async editGuildTemplate(guildId, templateCode: string, body: ModifyGuildTemplate): Promise<Camelize<DiscordTemplate>> {
|
||||
return await rest.patch<DiscordTemplate>(rest.routes.guilds.templates.guild(guildId, templateCode), { body })
|
||||
},
|
||||
|
||||
async editMessage(channelId, messageId, options) {
|
||||
return await rest.patch<DiscordMessage>(rest.routes.channels.message(channelId, messageId), options)
|
||||
async editMessage(channelId, messageId, body) {
|
||||
return await rest.patch<DiscordMessage>(rest.routes.channels.message(channelId, messageId), { body })
|
||||
},
|
||||
|
||||
async editOriginalInteractionResponse(token, options) {
|
||||
return await rest.patch<DiscordMessage>(rest.routes.interactions.responses.original(rest.applicationId, token), options)
|
||||
async editOriginalInteractionResponse(token, body) {
|
||||
return await rest.patch<DiscordMessage>(rest.routes.interactions.responses.original(rest.applicationId, token), {
|
||||
body,
|
||||
files: body.files,
|
||||
})
|
||||
},
|
||||
|
||||
async editOriginalWebhookMessage(webhookId, token, options) {
|
||||
return await rest.patch<DiscordMessage>(rest.routes.webhooks.original(webhookId, token, options), {
|
||||
type: InteractionResponseTypes.UpdateMessage,
|
||||
data: options,
|
||||
body: {
|
||||
type: InteractionResponseTypes.UpdateMessage,
|
||||
data: options,
|
||||
},
|
||||
files: options.files,
|
||||
})
|
||||
},
|
||||
|
||||
async editOwnVoiceState(guildId, options) {
|
||||
await rest.patch(rest.routes.guilds.voice(guildId), {
|
||||
channel_id: options.channelId,
|
||||
suppress: options.suppress,
|
||||
request_to_speak_timestamp: options.requestToSpeakTimestamp
|
||||
? new Date(options.requestToSpeakTimestamp).toISOString()
|
||||
: options.requestToSpeakTimestamp,
|
||||
body: {
|
||||
...options,
|
||||
request_to_speak_timestamp: options.requestToSpeakTimestamp
|
||||
? new Date(options.requestToSpeakTimestamp).toISOString()
|
||||
: options.requestToSpeakTimestamp,
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
async editScheduledEvent(guildId, eventId, options) {
|
||||
return await rest.patch<DiscordScheduledEvent>(rest.routes.guilds.events.event(guildId, eventId), options)
|
||||
async editScheduledEvent(guildId, eventId, body) {
|
||||
return await rest.patch<DiscordScheduledEvent>(rest.routes.guilds.events.event(guildId, eventId), { body })
|
||||
},
|
||||
|
||||
async editRole(guildId, roleId, options) {
|
||||
return await rest.patch<DiscordRole>(rest.routes.guilds.roles.one(guildId, roleId), options)
|
||||
async editRole(guildId, roleId, body) {
|
||||
return await rest.patch<DiscordRole>(rest.routes.guilds.roles.one(guildId, roleId), { body })
|
||||
},
|
||||
|
||||
async editRolePositions(guildId, options) {
|
||||
return await rest.patch<DiscordRole[]>(rest.routes.guilds.roles.all(guildId), options)
|
||||
async editRolePositions(guildId, body) {
|
||||
return await rest.patch<DiscordRole[]>(rest.routes.guilds.roles.all(guildId), { body })
|
||||
},
|
||||
|
||||
async editStageInstance(channelId, data) {
|
||||
return await rest.patch<DiscordStageInstance>(rest.routes.channels.stage(channelId), { topic: data.topic })
|
||||
async editStageInstance(channelId, topic, reason?: string) {
|
||||
return await rest.patch<DiscordStageInstance>(rest.routes.channels.stage(channelId), { body: { topic }, reason })
|
||||
},
|
||||
|
||||
async editUserVoiceState(guildId, options) {
|
||||
await rest.patch(rest.routes.guilds.voice(guildId, options.userId), {
|
||||
channel_id: options.channelId,
|
||||
suppress: options.suppress,
|
||||
user_id: options.userId,
|
||||
})
|
||||
await rest.patch(rest.routes.guilds.voice(guildId, options.userId), { body: options })
|
||||
},
|
||||
|
||||
async editWebhook(webhookId, options) {
|
||||
return await rest.patch<DiscordWebhook>(rest.routes.webhooks.id(webhookId), options)
|
||||
async editWebhook(webhookId, body) {
|
||||
return await rest.patch<DiscordWebhook>(rest.routes.webhooks.id(webhookId), { body })
|
||||
},
|
||||
|
||||
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) {
|
||||
return await rest.patch<DiscordWebhook>(rest.routes.webhooks.webhook(webhookId, token), options)
|
||||
async editWebhookWithToken(webhookId, token, body) {
|
||||
return await rest.patch<DiscordWebhook>(rest.routes.webhooks.webhook(webhookId, token), { body })
|
||||
},
|
||||
|
||||
async editWelcomeScreen(guildId, options) {
|
||||
return await rest.patch<DiscordWelcomeScreen>(rest.routes.guilds.welcome(guildId), options)
|
||||
async editWelcomeScreen(guildId, body) {
|
||||
return await rest.patch<DiscordWelcomeScreen>(rest.routes.guilds.welcome(guildId), { body })
|
||||
},
|
||||
|
||||
async editWidgetSettings(guildId, options) {
|
||||
return await rest.patch<DiscordGuildWidgetSettings>(rest.routes.guilds.widget(guildId), options)
|
||||
async editWidgetSettings(guildId, body) {
|
||||
return await rest.patch<DiscordGuildWidgetSettings>(rest.routes.guilds.widget(guildId), { body })
|
||||
},
|
||||
|
||||
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) {
|
||||
return await rest.post<DiscordFollowedChannel>(rest.routes.channels.follow(sourceChannelId), {
|
||||
webhook_channel_id: targetChannelId,
|
||||
} as DiscordFollowAnnouncementChannel)
|
||||
body: {
|
||||
webhook_channel_id: targetChannelId,
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
async getActiveThreads(guildId) {
|
||||
@@ -1458,7 +1473,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
||||
|
||||
async getDmChannel(userId) {
|
||||
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))
|
||||
},
|
||||
|
||||
// TODO: why that
|
||||
async sendFollowupMessage(token, options) {
|
||||
return await new Promise((resolve, reject) => {
|
||||
rest.sendRequest({
|
||||
url: rest.routes.webhooks.webhook(rest.applicationId, token),
|
||||
method: 'POST',
|
||||
body: options,
|
||||
method: 'POST',
|
||||
requestBodyOptions: { body: options, files: options.files },
|
||||
retryCount: 0,
|
||||
retryRequest: async function (options: SendRequestOptions) {
|
||||
retryRequest: async function(options: SendRequestOptions) {
|
||||
// TODO: should change to reprocess queue item
|
||||
await rest.sendRequest(options)
|
||||
},
|
||||
@@ -1689,14 +1705,15 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
||||
})
|
||||
},
|
||||
|
||||
// TODO: why that
|
||||
async sendInteractionResponse(interactionId, token, options) {
|
||||
await new Promise((resolve, reject) => {
|
||||
rest.sendRequest({
|
||||
url: rest.routes.interactions.responses.callback(interactionId, token),
|
||||
method: 'POST',
|
||||
body: options,
|
||||
requestBodyOptions: { body: options },
|
||||
retryCount: 0,
|
||||
retryRequest: async function (options: SendRequestOptions) {
|
||||
retryRequest: async function(options: SendRequestOptions) {
|
||||
// TODO: should change to reprocess queue item
|
||||
await rest.sendRequest(options)
|
||||
},
|
||||
@@ -1708,32 +1725,32 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
||||
})
|
||||
},
|
||||
|
||||
async sendMessage(channelId, options) {
|
||||
return await rest.post<DiscordMessage>(rest.routes.channels.messages(channelId), options)
|
||||
async sendMessage(channelId, body) {
|
||||
return await rest.post<DiscordMessage>(rest.routes.channels.messages(channelId), { body, files: body.files })
|
||||
},
|
||||
|
||||
async startThreadWithMessage(channelId, messageId, options) {
|
||||
return await rest.post<DiscordChannel>(rest.routes.channels.threads.message(channelId, messageId), options)
|
||||
async startThreadWithMessage(channelId, messageId, body) {
|
||||
return await rest.post<DiscordChannel>(rest.routes.channels.threads.message(channelId, messageId), { body })
|
||||
},
|
||||
|
||||
async startThreadWithoutMessage(channelId, options) {
|
||||
return await rest.post<DiscordChannel>(rest.routes.channels.threads.all(channelId), options)
|
||||
async startThreadWithoutMessage(channelId, body) {
|
||||
return await rest.post<DiscordChannel>(rest.routes.channels.threads.all(channelId), { body })
|
||||
},
|
||||
|
||||
async syncGuildTemplate(guildId) {
|
||||
return await rest.put<DiscordTemplate>(rest.routes.guilds.templates.all(guildId))
|
||||
},
|
||||
|
||||
async banMember(guildId, userId, options) {
|
||||
await rest.put<void>(rest.routes.guilds.members.ban(guildId, userId), options)
|
||||
async banMember(guildId, userId, body) {
|
||||
await rest.put<void>(rest.routes.guilds.members.ban(guildId, userId), { body })
|
||||
},
|
||||
|
||||
async editBotMember(guildId, options) {
|
||||
return await rest.patch<DiscordMember>(rest.routes.guilds.members.bot(guildId), options)
|
||||
async editBotMember(guildId, body) {
|
||||
return await rest.patch<DiscordMember>(rest.routes.guilds.members.bot(guildId), { body })
|
||||
},
|
||||
|
||||
async editMember(guildId, userId, options) {
|
||||
return await rest.patch<DiscordMemberWithUser>(rest.routes.guilds.members.member(guildId, userId), options)
|
||||
async editMember(guildId, userId, body) {
|
||||
return await rest.patch<DiscordMemberWithUser>(rest.routes.guilds.members.member(guildId, userId), { body })
|
||||
},
|
||||
|
||||
async getMember(guildId, userId) {
|
||||
@@ -1751,11 +1768,11 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
||||
},
|
||||
|
||||
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) {
|
||||
return await rest.post<{ pruned: number | null }>(rest.routes.guilds.members.prune(guildId), options)
|
||||
async pruneMembers(guildId, body) {
|
||||
return await rest.post<{ pruned: number | null }>(rest.routes.guilds.members.prune(guildId), { body })
|
||||
},
|
||||
|
||||
async searchMembers(guildId, query, options) {
|
||||
@@ -1767,19 +1784,19 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
|
||||
},
|
||||
|
||||
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) {
|
||||
await rest.post(rest.routes.channels.typing(channelId))
|
||||
},
|
||||
|
||||
async upsertGlobalApplicationCommands(commands) {
|
||||
return await rest.put<DiscordApplicationCommand[]>(rest.routes.interactions.commands.commands(rest.applicationId), commands)
|
||||
async upsertGlobalApplicationCommands(body) {
|
||||
return await rest.put<DiscordApplicationCommand[]>(rest.routes.interactions.commands.commands(rest.applicationId), { body })
|
||||
},
|
||||
|
||||
async upsertGuildApplicationCommands(guildId, commands) {
|
||||
return await rest.put<DiscordApplicationCommand[]>(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), commands)
|
||||
async upsertGuildApplicationCommands(guildId, body) {
|
||||
return await rest.put<DiscordApplicationCommand[]>(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), { body })
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -4,22 +4,6 @@ import type {
|
||||
BeginGuildPrune,
|
||||
BigString,
|
||||
Camelize,
|
||||
CreateApplicationCommand,
|
||||
CreateAutoModerationRuleOptions,
|
||||
CreateChannelInvite,
|
||||
CreateForumPostWithMessage,
|
||||
CreateGuild,
|
||||
CreateGuildBan,
|
||||
CreateGuildChannel,
|
||||
CreateGuildEmoji,
|
||||
CreateGuildFromTemplate,
|
||||
CreateGuildRole,
|
||||
CreateGuildStickerOptions,
|
||||
CreateMessageOptions,
|
||||
CreateScheduledEvent,
|
||||
CreateStageInstance,
|
||||
CreateTemplate,
|
||||
DeleteWebhookMessageOptions,
|
||||
CamelizedDiscordActiveThreads,
|
||||
CamelizedDiscordApplication,
|
||||
CamelizedDiscordApplicationCommand,
|
||||
@@ -56,6 +40,22 @@ import type {
|
||||
CamelizedDiscordVoiceRegion,
|
||||
CamelizedDiscordWebhook,
|
||||
CamelizedDiscordWelcomeScreen,
|
||||
CreateApplicationCommand,
|
||||
CreateAutoModerationRuleOptions,
|
||||
CreateChannelInvite,
|
||||
CreateForumPostWithMessage,
|
||||
CreateGuild,
|
||||
CreateGuildBan,
|
||||
CreateGuildChannel,
|
||||
CreateGuildEmoji,
|
||||
CreateGuildFromTemplate,
|
||||
CreateGuildRole,
|
||||
CreateGuildStickerOptions,
|
||||
CreateMessageOptions,
|
||||
CreateScheduledEvent,
|
||||
CreateStageInstance,
|
||||
CreateTemplate,
|
||||
DeleteWebhookMessageOptions,
|
||||
EditAutoModerationRuleOptions,
|
||||
EditBotMemberOptions,
|
||||
EditChannelPermissionOverridesOptions,
|
||||
@@ -64,9 +64,9 @@ import type {
|
||||
EditMessage,
|
||||
EditOwnVoiceState,
|
||||
EditScheduledEvent,
|
||||
EditStageInstanceOptions,
|
||||
EditUserVoiceState,
|
||||
ExecuteWebhook,
|
||||
FileContent,
|
||||
GetBans,
|
||||
GetGuildAuditLog,
|
||||
GetGuildPruneCountQuery,
|
||||
@@ -92,7 +92,6 @@ import type {
|
||||
SearchMembers,
|
||||
StartThreadWithMessage,
|
||||
StartThreadWithoutMessage,
|
||||
WithReason,
|
||||
} from '@discordeno/types'
|
||||
import type { InvalidRequestBucket } from './invalidBucket.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. */
|
||||
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. */
|
||||
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. */
|
||||
processRateLimitedPaths: () => void
|
||||
/** 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. */
|
||||
simplifyUrl: (url: string, method: RequestMethods) => string
|
||||
/** 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. */
|
||||
processRequest: (request: SendRequestOptions) => void
|
||||
/** 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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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.
|
||||
*
|
||||
@@ -487,7 +486,7 @@ export interface RestManager {
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
@@ -1187,6 +1186,7 @@ export interface RestManager {
|
||||
* Edits a stage instance.
|
||||
*
|
||||
* @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}.
|
||||
*
|
||||
* @remarks
|
||||
@@ -1196,7 +1196,7 @@ export interface RestManager {
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
@@ -2445,7 +2445,7 @@ export interface RestManager {
|
||||
export type RequestMethods = 'GET' | 'POST' | 'DELETE' | 'PATCH' | 'PUT'
|
||||
export type ApiVersions = 9 | 10
|
||||
|
||||
export interface CreateWebhook extends WithReason {
|
||||
export interface CreateWebhook {
|
||||
/** Name of the webhook (1-80 characters) */
|
||||
name: string
|
||||
/** Image url for the default webhook avatar */
|
||||
@@ -2454,25 +2454,23 @@ export interface CreateWebhook extends WithReason {
|
||||
|
||||
export interface CreateRequestBodyOptions {
|
||||
headers?: Record<string, string>
|
||||
method: RequestMethods
|
||||
body?: Record<string, unknown>
|
||||
body?: any
|
||||
unauthorized?: boolean
|
||||
url?: string
|
||||
reason?: string
|
||||
files?: FileContent[]
|
||||
}
|
||||
|
||||
export interface RequestBody {
|
||||
headers: Record<string, string>
|
||||
body: string | FormData
|
||||
body?: string | FormData
|
||||
method: RequestMethods
|
||||
}
|
||||
|
||||
export interface SendRequestOptions {
|
||||
/** The url to send the request to. */
|
||||
url: string
|
||||
/** The method to use when sending the request. */
|
||||
/** The method to use for sending the request. */
|
||||
method: RequestMethods
|
||||
/** The body to be sent in the request. */
|
||||
body?: Record<string, any>
|
||||
/** The amount of times this request has been retried. */
|
||||
retryCount: number
|
||||
/** 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 */
|
||||
bucketId?: string
|
||||
/** Additional request options, used for things like overriding authorization header. */
|
||||
options?: Record<string, any>
|
||||
requestBodyOptions?: CreateRequestBodyOptions
|
||||
}
|
||||
|
||||
export interface RestRateLimitedPath {
|
||||
@@ -2508,9 +2506,12 @@ export interface WebhookMessageEditor {
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
|
||||
@@ -57,7 +57,7 @@ describe('Member tests', () => {
|
||||
|
||||
it('Send a direct message', async () => {
|
||||
// DM test only on dd unit testing bot
|
||||
if (rest.applicationId.toString() !== "770381961553510451") return;
|
||||
if (rest.applicationId.toString() !== '770381961553510451') return
|
||||
// Itoh Alt ID
|
||||
const channel = await rest.getDmChannel(750661528360845322n)
|
||||
expect(channel?.id).to.exist
|
||||
|
||||
@@ -21,7 +21,7 @@ after(async () => {
|
||||
|
||||
describe('Send a message', () => {
|
||||
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')
|
||||
|
||||
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
|
||||
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)
|
||||
const [attachment] = message.attachments
|
||||
|
||||
|
||||
@@ -11,8 +11,12 @@ export const rest = createRestManager({
|
||||
})
|
||||
rest.deleteQueueDelay = 10000
|
||||
|
||||
const guild = await rest.createGuild({ name: 'ddenotester' });
|
||||
const channel = await rest.createChannel(guild.id, { name: "ddenotestchannel" });
|
||||
|
||||
export const e2ecache = {
|
||||
guild: await rest.createGuild({ name: 'ddenotester' }),
|
||||
guild,
|
||||
channel,
|
||||
deletedGuild: false,
|
||||
communityGuildId: E2E_TEST_GUILD_ID,
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ describe('[rest] manager', () => {
|
||||
version: 9,
|
||||
proxy: {
|
||||
baseUrl: 'https://localhost:8000',
|
||||
authorization: token
|
||||
}
|
||||
authorization: token,
|
||||
},
|
||||
} as const
|
||||
|
||||
const rest = createRestManager(options)
|
||||
@@ -80,7 +80,7 @@ describe('[rest] manager', () => {
|
||||
it('Will add method in front route if method is DELETE', () => {
|
||||
const rest = createRestManager({ token })
|
||||
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
|
||||
|
||||
- [Website](https://discordeno.github.io/discordeno/)
|
||||
- [Website](https://discordeno.js.org/)
|
||||
- [Documentation](https://doc.deno.land/https/deno.land/x/discordeno/mod.ts)
|
||||
- [Discord](https://discord.com/invite/5vBgXk3UcZ)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { FileContent } from './discordeno.js'
|
||||
import type {
|
||||
ActivityTypes,
|
||||
AllowedMentionsTypes,
|
||||
@@ -2564,8 +2563,6 @@ export interface DiscordCreateForumPostWithMessage {
|
||||
components?: DiscordMessageComponents[]
|
||||
/** IDs of up to 3 stickers in the server to send in the message */
|
||||
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} */
|
||||
payload_json?: string
|
||||
/** 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 */
|
||||
failIfNotExists: boolean
|
||||
}
|
||||
/** The contents of the file being sent */
|
||||
file?: FileContent | FileContent[]
|
||||
/** The contents of the files being sent */
|
||||
files?: FileContent[]
|
||||
/** The components you would like to have sent in this message */
|
||||
components?: MessageComponents
|
||||
/** 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>>
|
||||
/** Allowed mentions for the message */
|
||||
allowedMentions?: AllowedMentions
|
||||
/** The contents of the file being sent */
|
||||
file?: FileContent | FileContent[]
|
||||
/** The contents of the files being sent */
|
||||
files?: FileContent[]
|
||||
/** The customId you want to use for this modal response. */
|
||||
customId?: string
|
||||
/** The title you want to use for this modal response. */
|
||||
@@ -673,8 +673,8 @@ export interface ExecuteWebhook {
|
||||
avatarUrl?: string
|
||||
/** True if this is a TTS message */
|
||||
tts?: boolean
|
||||
/** The contents of the file being sent */
|
||||
file?: FileContent | FileContent[]
|
||||
/** The contents of the files being sent */
|
||||
files?: FileContent[]
|
||||
/** Embedded `rich` content */
|
||||
embeds?: Array<Camelize<DiscordEmbed>>
|
||||
/** Allowed mentions for the message */
|
||||
@@ -706,8 +706,8 @@ export interface CreateForumPostWithMessage extends WithReason {
|
||||
embeds?: Array<Camelize<DiscordEmbed>>
|
||||
/** Allowed mentions for the message */
|
||||
allowedMentions?: AllowedMentions
|
||||
/** The contents of the file being sent */
|
||||
file?: FileContent | FileContent[]
|
||||
/** The contents of the files being sent */
|
||||
files?: FileContent[]
|
||||
/** The components you would like to have sent in this message */
|
||||
components?: MessageComponents
|
||||
}
|
||||
@@ -890,8 +890,8 @@ export interface EditMessage {
|
||||
embeds?: Array<Camelize<DiscordEmbed>> | null
|
||||
/** Edit the flags of the message (only `SUPPRESS_EMBEDS` can currently be set/unset) */
|
||||
flags?: 4 | null
|
||||
/** The contents of the file being sent/edited */
|
||||
file?: FileContent | FileContent[] | null
|
||||
/** The contents of the files being sent/edited */
|
||||
files?: FileContent[] | null
|
||||
/** Allowed mentions for the message */
|
||||
allowedMentions?: AllowedMentions
|
||||
/** 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 */
|
||||
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) */
|
||||
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 */
|
||||
|
||||
@@ -149,6 +149,6 @@ and unofficial templates:
|
||||
|
||||
## Links
|
||||
|
||||
- [Website](https://discordeno.github.io/discordeno/)
|
||||
- [Website](https://discordeno.js.org/)
|
||||
- [Documentation](https://doc.deno.land/https/deno.land/x/discordeno/mod.ts)
|
||||
- [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