├── .github └── workflows │ └── publish-docs.yml ├── .gitignore ├── LICENSE ├── README.md ├── examples ├── js │ ├── createmessage.js │ ├── createreaction.js │ ├── events.js │ ├── fetchmessages.js │ └── fetchuser.js └── ts │ ├── createmessage.ts │ ├── createreaction.ts │ ├── events.ts │ ├── fetchmessages.ts │ └── fetchuser.ts ├── package-lock.json ├── package.json ├── src ├── bucket.ts ├── bucketcollection.ts ├── client.ts ├── clientsidechecks.ts ├── constants.ts ├── endpoints.ts ├── errors.ts ├── index.ts ├── request.ts ├── types.ts └── utils.ts └── tsconfig.json /.github/workflows/publish-docs.yml: -------------------------------------------------------------------------------- 1 | name: Deploy docs to Github Pages 2 | on: 3 | push: 4 | branches: 5 | - master 6 | jobs: 7 | publish-docs: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: actions/setup-node@v2 12 | - run: npm install 13 | - run: npm run typedoc 14 | - name: Deploy to GitHub Pages 15 | uses: JamesIves/github-pages-deploy-action@4.1.3 16 | with: 17 | branch: gh-pages 18 | folder: docs -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /lib 3 | /docs -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Dan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Detritus Client Rest 2 | ![npm](https://img.shields.io/npm/v/detritus-client-rest?style=flat-square) 3 | 4 | A pure-TypeScript library for just Discord's REST API. 5 | 6 | - [API Documentation](https://rest.detritusjs.com) 7 | - [npm](https://www.npmjs.com/package/detritus-client-rest) 8 | 9 | ## Installation 10 | 11 | - `$ npm i detritus-client-rest` 12 | - `$ yarn add detritus-client-rest` 13 | -------------------------------------------------------------------------------- /examples/js/createmessage.js: -------------------------------------------------------------------------------- 1 | const { Client } = require('../lib'); 2 | 3 | 4 | const token = ''; 5 | const client = new Client(token); 6 | 7 | const channelId = ''; 8 | (async () => { 9 | { 10 | const raw = await client.createMessage(channelId, 'Some Message'); 11 | // raw is the raw message from discord's api 12 | 13 | setTimeout(async () => { 14 | await client.deleteMessage(channelId, raw.id); 15 | }, 5000); 16 | } 17 | 18 | { 19 | const raw = await client.createMessage(channelId, { 20 | content: 'Some Message', 21 | embed: { 22 | description: 'A custom embed!', 23 | }, 24 | }); 25 | } 26 | 27 | { 28 | const raw = await client.createMessage(channelId, { 29 | file: {filename: 'file.txt', value: Buffer.from('Some file content')}, 30 | files: [ 31 | {filename: 'file2.txt', value: Buffer.from('file #2')}, 32 | ], 33 | }); 34 | } 35 | })(); 36 | -------------------------------------------------------------------------------- /examples/js/createreaction.js: -------------------------------------------------------------------------------- 1 | const { Client } = require('../lib'); 2 | 3 | 4 | const token = ''; 5 | const client = new Client(token); 6 | 7 | const channelId = ''; 8 | const messageId = ''; 9 | const emojis = ['👍🏿', '👌🏿', '👃🏿']; 10 | (async () => { 11 | for (let emoji of emojis) { 12 | await client.createReaction(channelId, messageId, emoji); 13 | } 14 | const rawMessage = await client.fetchMessage(channelId, messageId); 15 | console.log(rawMessage); 16 | })(); 17 | -------------------------------------------------------------------------------- /examples/js/events.js: -------------------------------------------------------------------------------- 1 | const { Client } = require('../lib'); 2 | 3 | 4 | const token = ''; 5 | const client = new Client(token); 6 | 7 | client.on('request', ({request, restRequest}) => { 8 | // request is the request object from `detritus-rest` while restRequest is our wrapped one 9 | }); 10 | 11 | client.on('response', ({response, restRequest}) => { 12 | const path = (response.request.route) ? response.request.route.path : null; 13 | if (response.ok) { 14 | console.log(`Response OK ${response.statusCode} ${response.request.url} ${(path) ? `(${path})` : ''}`); 15 | } else { 16 | console.log(`Response NOT OK ${response.statusCode} ${response.request.url} ${(path) ? `(${path})` : ''}`); 17 | } 18 | }); 19 | 20 | const userIds = ['']; 21 | (async () => { 22 | for (let userId of userIds) { 23 | await client.fetchUser(userId); 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /examples/js/fetchmessages.js: -------------------------------------------------------------------------------- 1 | const { Client } = require('../lib'); 2 | 3 | 4 | const token = ''; 5 | const client = new Client(token); 6 | 7 | const channelId = ''; 8 | (async () => { 9 | { 10 | const raw = await client.fetchMessages(channelId, {limit: 100}); 11 | } 12 | 13 | { 14 | // fetch ALL of a channel's messages since the beginning of its creation 15 | const messages = []; 16 | 17 | let atEnd = false; 18 | let lastMessageId = 0; 19 | while (!atEnd) { 20 | const raw = await client.fetchMessages(channelId, { 21 | after: lastMessageId, 22 | limit: 100, 23 | }); 24 | if (raw.length) { 25 | messages = [...raw, ...messages]; 26 | lastMessageId = raw[0].id; 27 | } else { 28 | atEnd = true; 29 | } 30 | } 31 | 32 | // messages now has all the messages from a channel, sorted from newest to oldest 33 | } 34 | })(); 35 | -------------------------------------------------------------------------------- /examples/js/fetchuser.js: -------------------------------------------------------------------------------- 1 | const { Client } = require('../lib'); 2 | 3 | 4 | const token = ''; 5 | const client = new Client(token); 6 | 7 | const userId = ''; 8 | (async () => { 9 | const user = await client.fetchUser(userId); 10 | console.log(user); 11 | })(); 12 | -------------------------------------------------------------------------------- /examples/ts/createmessage.ts: -------------------------------------------------------------------------------- 1 | import { Client } from '../lib'; 2 | 3 | const token = ''; 4 | const client = new Client(token); 5 | 6 | const channelId = ''; 7 | (async () => { 8 | { 9 | const raw = await client.createMessage(channelId, 'Some Message'); 10 | // raw is the raw message from discord's api 11 | 12 | setTimeout(async () => { 13 | await client.deleteMessage(channelId, raw.id); 14 | }, 5000); 15 | } 16 | 17 | { 18 | const raw = await client.createMessage(channelId, { 19 | content: 'Some Message', 20 | embed: { 21 | description: 'A custom embed!', 22 | }, 23 | }); 24 | } 25 | 26 | { 27 | const raw = await client.createMessage(channelId, { 28 | file: {filename: 'file.txt', value: Buffer.from('Some file content')}, 29 | files: [ 30 | {filename: 'file2.txt', value: Buffer.from('file #2')}, 31 | ], 32 | }); 33 | } 34 | })(); 35 | -------------------------------------------------------------------------------- /examples/ts/createreaction.ts: -------------------------------------------------------------------------------- 1 | import { Client } from '../lib'; 2 | 3 | 4 | const token = ''; 5 | const client = new Client(token); 6 | 7 | const channelId = ''; 8 | const messageId = ''; 9 | const emojis = ['👍🏿', '👌🏿', '👃🏿']; 10 | (async () => { 11 | for (let emoji of emojis) { 12 | await client.createReaction(channelId, messageId, emoji); 13 | } 14 | const rawMessage = await client.fetchMessage(channelId, messageId); 15 | console.log(rawMessage); 16 | })(); 17 | -------------------------------------------------------------------------------- /examples/ts/events.ts: -------------------------------------------------------------------------------- 1 | import { Client } from '../lib'; 2 | 3 | 4 | const token = ''; 5 | const client = new Client(token); 6 | 7 | client.on('request', ({request, restRequest}) => { 8 | // request is the request object from `detritus-rest` while restRequest is our wrapped one 9 | }); 10 | 11 | client.on('response', ({response, restRequest}) => { 12 | const path = (response.request.route) ? response.request.route.path : null; 13 | if (response.ok) { 14 | console.log(`Response OK ${response.statusCode} ${response.request.url} ${(path) ? `(${path})` : ''}`); 15 | } else { 16 | console.log(`Response NOT OK ${response.statusCode} ${response.request.url} ${(path) ? `(${path})` : ''}`); 17 | } 18 | }); 19 | 20 | const userIds = ['']; 21 | (async () => { 22 | for (let userId of userIds) { 23 | await client.fetchUser(userId); 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /examples/ts/fetchmessages.ts: -------------------------------------------------------------------------------- 1 | import { Client } from '../lib'; 2 | 3 | 4 | const token = ''; 5 | const client = new Client(token); 6 | 7 | const channelId = ''; 8 | (async () => { 9 | { 10 | const raw = await client.fetchMessages(channelId, {limit: 100}); 11 | } 12 | 13 | { 14 | // fetch ALL of a channel's messages since the beginning of its creation 15 | const messages: Array = []; 16 | 17 | let atEnd = false; 18 | let lastMessageId = 0; 19 | while (!atEnd) { 20 | const raw = await client.fetchMessages(channelId, { 21 | after: lastMessageId, 22 | limit: 100, 23 | }); 24 | if (raw.length) { 25 | messages = [...raw, ...messages]; 26 | lastMessageId = raw[0].id; 27 | } else { 28 | atEnd = true; 29 | } 30 | } 31 | 32 | // messages now has all the messages from a channel, sorted from newest to oldest 33 | } 34 | })(); 35 | -------------------------------------------------------------------------------- /examples/ts/fetchuser.ts: -------------------------------------------------------------------------------- 1 | import { Client } from '../lib'; 2 | 3 | 4 | const token = ''; 5 | const client = new Client(token); 6 | 7 | const userId = ''; 8 | (async () => { 9 | const rawUser = await client.fetchUser(userId); 10 | console.log(rawUser); 11 | })(); 12 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "detritus-client-rest", 3 | "version": "0.10.2", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/node": { 8 | "version": "14.17.2", 9 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.2.tgz", 10 | "integrity": "sha512-sld7b/xmFum66AAKuz/rp/CUO8+98fMpyQ3SBfzzBNGMd/1iHBTAg9oyAvcYlAj46bpc74r91jSw2iFdnx29nw==", 11 | "dev": true 12 | }, 13 | "@types/node-fetch": { 14 | "version": "2.5.10", 15 | "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.10.tgz", 16 | "integrity": "sha512-IpkX0AasN44hgEad0gEF/V6EgR5n69VEqPEgnmoM8GsIGro3PowbWs4tR6IhxUTyPLpOn+fiGG6nrQhcmoCuIQ==", 17 | "dev": true, 18 | "requires": { 19 | "@types/node": "*", 20 | "form-data": "^3.0.0" 21 | } 22 | }, 23 | "asynckit": { 24 | "version": "0.4.0", 25 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 26 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 27 | }, 28 | "at-least-node": { 29 | "version": "1.0.0", 30 | "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", 31 | "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", 32 | "dev": true 33 | }, 34 | "balanced-match": { 35 | "version": "1.0.2", 36 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 37 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 38 | "dev": true 39 | }, 40 | "brace-expansion": { 41 | "version": "1.1.11", 42 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 43 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 44 | "dev": true, 45 | "requires": { 46 | "balanced-match": "^1.0.0", 47 | "concat-map": "0.0.1" 48 | } 49 | }, 50 | "colors": { 51 | "version": "1.4.0", 52 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", 53 | "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", 54 | "dev": true 55 | }, 56 | "combined-stream": { 57 | "version": "1.0.8", 58 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 59 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 60 | "requires": { 61 | "delayed-stream": "~1.0.0" 62 | } 63 | }, 64 | "concat-map": { 65 | "version": "0.0.1", 66 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 67 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 68 | "dev": true 69 | }, 70 | "delayed-stream": { 71 | "version": "1.0.0", 72 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 73 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 74 | }, 75 | "detritus-rest": { 76 | "version": "0.7.0", 77 | "resolved": "https://registry.npmjs.org/detritus-rest/-/detritus-rest-0.7.0.tgz", 78 | "integrity": "sha512-T5FNXpyv5F69ZXEz6z8mWo5yiz7Mhrg+HQsZumih/uDeqf3+1AvZgNI4XLscG1D56F0o5DSyXkoOxDgd2oeTgA==", 79 | "requires": { 80 | "form-data": "^3.0.0", 81 | "node-fetch": "^2.6.1" 82 | } 83 | }, 84 | "detritus-utils": { 85 | "version": "0.4.0", 86 | "resolved": "https://registry.npmjs.org/detritus-utils/-/detritus-utils-0.4.0.tgz", 87 | "integrity": "sha512-XO9crk1eCOecajzOg4WMsvcgXV/3GAltV0nt+kXXmglwcKyh/5DpQ7jmQ/2HycEN0dGBdgLCLPzYMxrWPN9gpw==" 88 | }, 89 | "form-data": { 90 | "version": "3.0.0", 91 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", 92 | "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", 93 | "requires": { 94 | "asynckit": "^0.4.0", 95 | "combined-stream": "^1.0.8", 96 | "mime-types": "^2.1.12" 97 | } 98 | }, 99 | "fs-extra": { 100 | "version": "9.1.0", 101 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", 102 | "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", 103 | "dev": true, 104 | "requires": { 105 | "at-least-node": "^1.0.0", 106 | "graceful-fs": "^4.2.0", 107 | "jsonfile": "^6.0.1", 108 | "universalify": "^2.0.0" 109 | } 110 | }, 111 | "fs.realpath": { 112 | "version": "1.0.0", 113 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 114 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 115 | "dev": true 116 | }, 117 | "function-bind": { 118 | "version": "1.1.1", 119 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 120 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 121 | "dev": true 122 | }, 123 | "glob": { 124 | "version": "7.1.7", 125 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", 126 | "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", 127 | "dev": true, 128 | "requires": { 129 | "fs.realpath": "^1.0.0", 130 | "inflight": "^1.0.4", 131 | "inherits": "2", 132 | "minimatch": "^3.0.4", 133 | "once": "^1.3.0", 134 | "path-is-absolute": "^1.0.0" 135 | } 136 | }, 137 | "graceful-fs": { 138 | "version": "4.2.6", 139 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", 140 | "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", 141 | "dev": true 142 | }, 143 | "handlebars": { 144 | "version": "4.7.7", 145 | "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", 146 | "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", 147 | "dev": true, 148 | "requires": { 149 | "minimist": "^1.2.5", 150 | "neo-async": "^2.6.0", 151 | "source-map": "^0.6.1", 152 | "uglify-js": "^3.1.4", 153 | "wordwrap": "^1.0.0" 154 | } 155 | }, 156 | "has": { 157 | "version": "1.0.3", 158 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 159 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 160 | "dev": true, 161 | "requires": { 162 | "function-bind": "^1.1.1" 163 | } 164 | }, 165 | "inflight": { 166 | "version": "1.0.6", 167 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 168 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 169 | "dev": true, 170 | "requires": { 171 | "once": "^1.3.0", 172 | "wrappy": "1" 173 | } 174 | }, 175 | "inherits": { 176 | "version": "2.0.4", 177 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 178 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 179 | "dev": true 180 | }, 181 | "interpret": { 182 | "version": "1.4.0", 183 | "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", 184 | "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", 185 | "dev": true 186 | }, 187 | "is-core-module": { 188 | "version": "2.4.0", 189 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", 190 | "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", 191 | "dev": true, 192 | "requires": { 193 | "has": "^1.0.3" 194 | } 195 | }, 196 | "jsonfile": { 197 | "version": "6.1.0", 198 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", 199 | "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", 200 | "dev": true, 201 | "requires": { 202 | "graceful-fs": "^4.1.6", 203 | "universalify": "^2.0.0" 204 | } 205 | }, 206 | "lodash": { 207 | "version": "4.17.21", 208 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 209 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 210 | "dev": true 211 | }, 212 | "lru-cache": { 213 | "version": "5.1.1", 214 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", 215 | "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", 216 | "dev": true, 217 | "requires": { 218 | "yallist": "^3.0.2" 219 | } 220 | }, 221 | "lunr": { 222 | "version": "2.3.9", 223 | "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", 224 | "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", 225 | "dev": true 226 | }, 227 | "marked": { 228 | "version": "2.0.6", 229 | "resolved": "https://registry.npmjs.org/marked/-/marked-2.0.6.tgz", 230 | "integrity": "sha512-S2mYj0FzTQa0dLddssqwRVW4EOJOVJ355Xm2Vcbm+LU7GQRGWvwbO5K87OaPSOux2AwTSgtPPaXmc8sDPrhn2A==", 231 | "dev": true 232 | }, 233 | "mime-db": { 234 | "version": "1.45.0", 235 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz", 236 | "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==" 237 | }, 238 | "mime-types": { 239 | "version": "2.1.28", 240 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz", 241 | "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==", 242 | "requires": { 243 | "mime-db": "1.45.0" 244 | } 245 | }, 246 | "minimatch": { 247 | "version": "3.0.4", 248 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 249 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 250 | "dev": true, 251 | "requires": { 252 | "brace-expansion": "^1.1.7" 253 | } 254 | }, 255 | "minimist": { 256 | "version": "1.2.5", 257 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 258 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", 259 | "dev": true 260 | }, 261 | "neo-async": { 262 | "version": "2.6.2", 263 | "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", 264 | "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", 265 | "dev": true 266 | }, 267 | "node-fetch": { 268 | "version": "2.6.1", 269 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", 270 | "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" 271 | }, 272 | "once": { 273 | "version": "1.4.0", 274 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 275 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 276 | "dev": true, 277 | "requires": { 278 | "wrappy": "1" 279 | } 280 | }, 281 | "onigasm": { 282 | "version": "2.2.5", 283 | "resolved": "https://registry.npmjs.org/onigasm/-/onigasm-2.2.5.tgz", 284 | "integrity": "sha512-F+th54mPc0l1lp1ZcFMyL/jTs2Tlq4SqIHKIXGZOR/VkHkF9A7Fr5rRr5+ZG/lWeRsyrClLYRq7s/yFQ/XhWCA==", 285 | "dev": true, 286 | "requires": { 287 | "lru-cache": "^5.1.1" 288 | } 289 | }, 290 | "path-is-absolute": { 291 | "version": "1.0.1", 292 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 293 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 294 | "dev": true 295 | }, 296 | "path-parse": { 297 | "version": "1.0.7", 298 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 299 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 300 | "dev": true 301 | }, 302 | "progress": { 303 | "version": "2.0.3", 304 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", 305 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", 306 | "dev": true 307 | }, 308 | "rechoir": { 309 | "version": "0.6.2", 310 | "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", 311 | "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", 312 | "dev": true, 313 | "requires": { 314 | "resolve": "^1.1.6" 315 | } 316 | }, 317 | "resolve": { 318 | "version": "1.20.0", 319 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", 320 | "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", 321 | "dev": true, 322 | "requires": { 323 | "is-core-module": "^2.2.0", 324 | "path-parse": "^1.0.6" 325 | } 326 | }, 327 | "shelljs": { 328 | "version": "0.8.4", 329 | "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", 330 | "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", 331 | "dev": true, 332 | "requires": { 333 | "glob": "^7.0.0", 334 | "interpret": "^1.0.0", 335 | "rechoir": "^0.6.2" 336 | } 337 | }, 338 | "shiki": { 339 | "version": "0.9.3", 340 | "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.9.3.tgz", 341 | "integrity": "sha512-NEjg1mVbAUrzRv2eIcUt3TG7X9svX7l3n3F5/3OdFq+/BxUdmBOeKGiH4icZJBLHy354Shnj6sfBTemea2e7XA==", 342 | "dev": true, 343 | "requires": { 344 | "onigasm": "^2.2.5", 345 | "vscode-textmate": "^5.2.0" 346 | } 347 | }, 348 | "source-map": { 349 | "version": "0.6.1", 350 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 351 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 352 | "dev": true 353 | }, 354 | "typedoc": { 355 | "version": "0.20.36", 356 | "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.20.36.tgz", 357 | "integrity": "sha512-qFU+DWMV/hifQ9ZAlTjdFO9wbUIHuUBpNXzv68ZyURAP9pInjZiO4+jCPeAzHVcaBCHER9WL/+YzzTt6ZlN/Nw==", 358 | "dev": true, 359 | "requires": { 360 | "colors": "^1.4.0", 361 | "fs-extra": "^9.1.0", 362 | "handlebars": "^4.7.7", 363 | "lodash": "^4.17.21", 364 | "lunr": "^2.3.9", 365 | "marked": "^2.0.3", 366 | "minimatch": "^3.0.0", 367 | "progress": "^2.0.3", 368 | "shelljs": "^0.8.4", 369 | "shiki": "^0.9.3", 370 | "typedoc-default-themes": "^0.12.10" 371 | } 372 | }, 373 | "typedoc-default-themes": { 374 | "version": "0.12.10", 375 | "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.12.10.tgz", 376 | "integrity": "sha512-fIS001cAYHkyQPidWXmHuhs8usjP5XVJjWB8oZGqkTowZaz3v7g3KDZeeqE82FBrmkAnIBOY3jgy7lnPnqATbA==", 377 | "dev": true 378 | }, 379 | "typescript": { 380 | "version": "4.3.2", 381 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz", 382 | "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==", 383 | "dev": true 384 | }, 385 | "uglify-js": { 386 | "version": "3.13.8", 387 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.8.tgz", 388 | "integrity": "sha512-PvFLMFIQHfIjFFlvAch69U2IvIxK9TNzNWt1SxZGp9JZ/v70yvqIQuiJeVPPtUMOzoNt+aNRDk4wgxb34wvEqA==", 389 | "dev": true, 390 | "optional": true 391 | }, 392 | "universalify": { 393 | "version": "2.0.0", 394 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", 395 | "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", 396 | "dev": true 397 | }, 398 | "vscode-textmate": { 399 | "version": "5.4.0", 400 | "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.4.0.tgz", 401 | "integrity": "sha512-c0Q4zYZkcLizeYJ3hNyaVUM2AA8KDhNCA3JvXY8CeZSJuBdAy3bAvSbv46RClC4P3dSO9BdwhnKEx2zOo6vP/w==", 402 | "dev": true 403 | }, 404 | "wordwrap": { 405 | "version": "1.0.0", 406 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", 407 | "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", 408 | "dev": true 409 | }, 410 | "wrappy": { 411 | "version": "1.0.2", 412 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 413 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 414 | "dev": true 415 | }, 416 | "yallist": { 417 | "version": "3.1.1", 418 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", 419 | "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", 420 | "dev": true 421 | } 422 | } 423 | } 424 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "cakedan", 3 | "bugs": { 4 | "url": "https://github.com/detritusjs/client-rest/issues" 5 | }, 6 | "files": [ 7 | "lib/**/*" 8 | ], 9 | "dependencies": { 10 | "detritus-rest": "^0.7.0", 11 | "detritus-utils": "^0.4.0" 12 | }, 13 | "description": "A minimalistic TypeScript library to interact with all, or most, of Discord's rest endpoints", 14 | "devDependencies": { 15 | "@types/node": "^14.17.1", 16 | "@types/node-fetch": "^2.5.10", 17 | "typedoc": "^0.20.36", 18 | "typescript": "^4.2.4" 19 | }, 20 | "homepage": "https://github.com/detritusjs/client-rest#readme", 21 | "keywords": [ 22 | "rest", 23 | "library" 24 | ], 25 | "license": "MIT", 26 | "main": "lib/index.js", 27 | "name": "detritus-client-rest", 28 | "peerDependencies": {}, 29 | "repository": { 30 | "type": "git", 31 | "url": "git+https://github.com/detritusjs/client-rest.git" 32 | }, 33 | "scripts": { 34 | "build": "tsc", 35 | "prepare": "npm run build", 36 | "test": "echo \"Error: no test specified\" && exit 1", 37 | "typedoc": "typedoc" 38 | }, 39 | "types": "lib/index.d.ts", 40 | "version": "0.10.5" 41 | } 42 | -------------------------------------------------------------------------------- /src/bucket.ts: -------------------------------------------------------------------------------- 1 | import { Timers } from 'detritus-utils'; 2 | 3 | import { RestRequest } from './request'; 4 | 5 | 6 | export interface RatelimitQueue { 7 | request: RestRequest, 8 | reject: any, 9 | resolve: any, 10 | } 11 | 12 | export interface RatelimitDetails { 13 | limit: number, 14 | remaining: number, 15 | resetAfter: number, 16 | resetAt: number, 17 | resetAtLocal: number, 18 | } 19 | 20 | export class Bucket { 21 | readonly key: string = ''; 22 | readonly ratelimit: RatelimitDetails = { 23 | limit: Infinity, 24 | remaining: Infinity, 25 | resetAfter: Infinity, 26 | resetAt: Infinity, 27 | resetAtLocal: Infinity, 28 | }; 29 | readonly timeout = new Timers.Timeout(); 30 | 31 | locked: boolean = false; 32 | lockedUntil: number = 0; 33 | queue: Array = []; 34 | 35 | constructor(key: string) { 36 | this.key = key; 37 | 38 | Object.defineProperties(this, { 39 | queue: {enumerable: false}, 40 | timeout: {enumerable: false}, 41 | }); 42 | } 43 | 44 | get length(): number { 45 | return this.queue.length; 46 | } 47 | 48 | get size(): number { 49 | return this.queue.length; 50 | } 51 | 52 | get unlockIn(): number { 53 | return Math.max(this.lockedUntil - Date.now(), 0); 54 | } 55 | 56 | setRatelimit( 57 | limit: number, 58 | remaining: number, 59 | reset: number, 60 | resetAfter: number, 61 | ): this { 62 | if (isNaN(limit)) { 63 | limit = Infinity; 64 | } 65 | if (isNaN(remaining)) { 66 | remaining = Infinity; 67 | } 68 | 69 | this.ratelimit.limit = limit; 70 | if (this.ratelimit.remaining === Infinity) { 71 | this.ratelimit.remaining = remaining; 72 | } else if (remaining <= this.ratelimit.remaining) { 73 | this.ratelimit.remaining = remaining; 74 | } 75 | 76 | if (resetAfter < this.ratelimit.resetAfter) { 77 | this.ratelimit.resetAfter = resetAfter; 78 | this.ratelimit.resetAt = reset; 79 | } 80 | this.ratelimit.resetAtLocal = Math.min( 81 | Date.now() + resetAfter, 82 | this.ratelimit.resetAtLocal, 83 | ); 84 | this.lockedUntil = this.ratelimit.resetAtLocal; 85 | 86 | return this; 87 | } 88 | 89 | lock(unlockIn: number): void { 90 | if (!unlockIn) { 91 | this.timeout.stop(); 92 | this.locked = false; 93 | return this.shift(); 94 | } 95 | 96 | this.locked = true; 97 | this.lockedUntil = Date.now() + unlockIn; 98 | } 99 | 100 | add(delayed: RatelimitQueue, unshift: boolean = false) { 101 | if (unshift) { 102 | this.queue.unshift(delayed); 103 | } else { 104 | this.queue.push(delayed); 105 | } 106 | this.shift(); 107 | } 108 | 109 | shift(): void { 110 | if (this.size) { 111 | if (this.locked && !this.timeout.hasStarted) { 112 | if (this.lockedUntil <= Date.now()) { 113 | this.locked = false; 114 | } else { 115 | this.timeout.start(this.unlockIn, () => this.reset(), false); 116 | } 117 | } 118 | 119 | if (!this.locked) { 120 | const delayed = this.queue.shift(); 121 | delayed.request.send() 122 | .then(delayed.resolve) 123 | .catch(delayed.reject) 124 | .then(() => this.shift()); 125 | } 126 | } 127 | } 128 | 129 | reset(): void { 130 | this.ratelimit.limit = Infinity; 131 | this.ratelimit.remaining = Infinity; 132 | this.ratelimit.resetAfter = Infinity; 133 | this.ratelimit.resetAt = Infinity; 134 | this.ratelimit.resetAtLocal = Infinity; 135 | this.locked = false; 136 | this.shift(); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/bucketcollection.ts: -------------------------------------------------------------------------------- 1 | import { BaseCollection, BaseCollectionOptions } from 'detritus-utils'; 2 | 3 | import { Bucket } from './bucket'; 4 | 5 | 6 | export class BucketCollection extends BaseCollection { 7 | insert(bucket: Bucket) { 8 | this.set(bucket.key, bucket); 9 | } 10 | 11 | resetExpire(bucket: Bucket) { 12 | if (this.has(bucket.key)) { 13 | this.get(bucket.key); 14 | } else { 15 | this.insert(bucket); 16 | } 17 | } 18 | 19 | startInterval(): void { 20 | super.startInterval(); 21 | if (this.interval) { 22 | this.interval.unref(); 23 | } 24 | } 25 | 26 | get [Symbol.toStringTag](): string { 27 | return `Buckets (${this.size.toLocaleString()} items)`; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/clientsidechecks.ts: -------------------------------------------------------------------------------- 1 | export enum Types { 2 | ARRAY = 'array', 3 | BOOLEAN = 'boolean', 4 | NUMBER = 'number', 5 | OBJECT = 'object', 6 | SNOWFLAKE = 'snowflake', 7 | STRING = 'string', 8 | } 9 | 10 | export const Regexes = { 11 | [Types.SNOWFLAKE]: /^\d+|@me$/, 12 | }; 13 | 14 | export function bufferToBase64( 15 | buffer?: Buffer | string | null, 16 | ): string | null | undefined { 17 | if (buffer instanceof Buffer) { 18 | const mimetype = 'image/png'; 19 | // just put image/png for now, discord checks the file for the mimetype anyways 20 | return `data:${mimetype};base64,${buffer.toString('base64')}`; 21 | } 22 | return buffer; 23 | } 24 | 25 | export function verifyData(data: { 26 | [key: string]: any, 27 | }, verification: { 28 | [key: string]: { 29 | required?: boolean, 30 | type?: string, 31 | }, 32 | }): void { 33 | for (let key in verification) { 34 | const valueOptions = verification[key]; 35 | if (!(key in data) || data[key] === undefined) { 36 | if (valueOptions.required) { 37 | throw new Error(`${key} is required.`); 38 | } 39 | continue; 40 | } 41 | 42 | let value = data[key]; 43 | switch (valueOptions.type) { 44 | case Types.ARRAY: { 45 | if (!Array.isArray(value)) { 46 | throw new Error(`${key} has to be an array.`); 47 | } 48 | }; break; 49 | case Types.BOOLEAN: { 50 | value = Boolean(value); 51 | }; break; 52 | case Types.NUMBER: { 53 | value = parseInt(value); 54 | if (value === NaN) { 55 | throw new Error(`${key} has to be an integer.`); 56 | } 57 | }; break; 58 | case Types.OBJECT: { 59 | if (typeof(value) !== Types.OBJECT) { 60 | throw new Error(`${key} has to be an object.`); 61 | } 62 | }; break; 63 | case Types.SNOWFLAKE: { 64 | if (typeof(value) !== Types.STRING && typeof(value) !== Types.NUMBER) { 65 | if (!Regexes[Types.SNOWFLAKE].exec(value)) { 66 | throw new Error(`${key} has to be a snowflake.`); 67 | } 68 | } 69 | }; break; 70 | case Types.STRING: { 71 | value = String(value); 72 | }; break; 73 | } 74 | data[key] = value; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | export { HTTPMethods } from 'detritus-rest/lib/constants'; 2 | 3 | export const Package = Object.freeze({ 4 | URL: 'https://github.com/detritusjs/client-rest', 5 | VERSION: '0.10.5', 6 | }); 7 | 8 | 9 | export const ApiVersion = 9; 10 | 11 | export enum AuthTypes { 12 | BEARER = 'BEARER', 13 | BOT = 'BOT', 14 | USER = 'USER', 15 | } 16 | 17 | export enum ActivityActionTypes { 18 | JOIN = 1, 19 | SPECTATE = 2, 20 | LISTEN = 3, 21 | WATCH = 4, 22 | JOIN_REQUEST = 5, 23 | } 24 | 25 | export enum DiscordAbortCodes { 26 | UNKNOWN_ACCOUNT = 10001, 27 | UNKNOWN_APPLICATION = 10002, 28 | UNKNOWN_CHANNEL = 10003, 29 | UNKNOWN_GUILD = 10004, 30 | UNKNOWN_INTEGRATION = 10005, 31 | UNKNOWN_INVITE = 10006, 32 | UNKNOWN_MEMBER = 10007, 33 | UNKNOWN_MESSAGE = 10008, 34 | UNKNOWN_OVERWRITE = 10009, 35 | UNKNOWN_PLATFORM = 10010, 36 | UNKNOWN_ROLE = 10011, 37 | UNKNOWN_TOKEN = 10012, 38 | UNKNOWN_USER = 10013, 39 | UNKNOWN_EMOJI = 10014, 40 | UNKNOWN_WEBHOOK = 10015, 41 | UNKNOWN_GIFT_CODE = 10038, 42 | 43 | BOT_DISALLOWED = 20001, 44 | BOT_REQUIRED = 20002, 45 | RPC_PROXY_DISALLOWED = 20003, 46 | EXPLICIT_CONTENT = 20009, 47 | ACCOUNT_SCHEDULED_FOR_DELETION = 20011, 48 | USER_NOT_AUTHORIZED_FOR_APPLICATION = 20012, 49 | ACCOUNT_DISABLED = 20013, 50 | SLOWMODE_RATE_LIMITED = 20016, 51 | CHANNEL_FOLLOWING_EDIT_RATE_LIMITED = 20017, 52 | UNDER_MINIMUM_AGE = 20024, 53 | 54 | TOO_MANY_USER_GUILDS = 30001, 55 | TOO_MANY_BOT_GUILDS = 30001, 56 | TOO_MANY_FRIENDS = 30002, 57 | TOO_MANY_PINS_IN_CHANNEL = 30003, 58 | TOO_MANY_RECIPIENTS = 30004, 59 | TOO_MANY_GUILD_ROLES = 30005, 60 | TOO_MANY_USING_USERNAME = 30006, 61 | TOO_MANY_WEBHOOKS = 30007, 62 | TOO_MANY_EMOJI = 30008, 63 | TOO_MANY_REACTIONS = 30010, 64 | TOO_MANY_GUILD_CHANNELS = 30013, 65 | TOO_MANY_ATTACHMENTS = 30015, 66 | TOO_MANY_ANIMATED_EMOJI = 30018, 67 | NOT_ENOUGH_GUILD_MEMBERS = 30029, 68 | 69 | UNAUTHORIZED = 40001, 70 | EMAIL_VERIFICATION_REQUIRED = 40002, 71 | RATE_LIMIT_DM_OPEN = 40003, 72 | SEND_MESSAGE_TEMPORARILY_DISABLED = 40004, 73 | USER_BANNED = 40007, 74 | CONNECTION_REVOKED = 40012, 75 | DELETE_ACCOUNT_TRANSFER_TEAM_OWNERSHIP = 40028, 76 | 77 | INVALID_ACCESS = 50001, 78 | INVALID_ACCOUNT_TYPE = 50002, 79 | INVALID_ACTION_DM = 50003, 80 | INVALID_EMBED_DISABLED = 50004, 81 | INVALID_MESSAGE_AUTHOR = 50005, 82 | INVALID_MESSAGE_EMPTY = 50006, 83 | INVALID_MESSAGE_SEND_USER = 50007, 84 | INVALID_MESSAGE_SEND_NON_TEXT = 50008, 85 | INVALID_MESSAGE_VERIFICATION_LEVEL = 50009, 86 | INVALID_OAUTH_APP_BOT = 50010, 87 | INVALID_OAUTH_APP_LIMIT = 50011, 88 | INVALID_OAUTH_STATE = 50012, 89 | INVALID_PERMISSIONS = 50013, 90 | INVALID_TOKEN = 50014, 91 | INVALID_NOTE = 50015, 92 | INVALID_BULK_DELETE_COUNT = 50016, 93 | INVALID_MFA_LEVEL = 50017, 94 | INVALID_PASSWORD = 50018, 95 | INVALID_PIN_MESSAGE_CHANNEL = 50019, 96 | INVALID_INVITE_CODE = 50020, 97 | INVALID_SYSTEM_MESSAGE_ACTION = 50021, 98 | INVALID_PHONE_NUMBER = 50022, 99 | INVALID_CLIENT_ID = 50023, 100 | INVALID_CHANNEL_TYPE = 50024, 101 | INVALID_OAUTH2_ACCESS_TOKEN = 50025, 102 | INVALID_OAUTH2_MISSING_SCOPE = 50026, 103 | INVALID_WEBHOOK_TOKEN = 50027, 104 | INVALID_BULK_DELETE = 50034, 105 | INVALID_FORM_BODY = 50035, 106 | INVALID_INVITE_ACCEPTED = 50036, 107 | INVALID_API_VERSION = 50041, 108 | INVALID_FILE_SIZE = 50045, 109 | INVALID_FILE = 50046, 110 | INVALID_GIFT_REDEMPTION_EXHAUSTED = 50050, 111 | INVALID_GIFT_REDEMPTION_OWNED = 50051, 112 | INVALID_GIFT_SELF_REDEMPTION = 50054, 113 | INVALID_GIFT_REDEMPTION_SUBSCRIPTION_MANAGED = 100021, 114 | INVALID_GIFT_REDEMPTION_SUBSCRIPTION_INCOMPATIBLE = 100023, 115 | INVALID_GIFT_REDEMPTION_INVOICE_OPEN = 100024, 116 | 117 | MFA_ENABLED = 60001, 118 | MFA_DISABLED = 60002, 119 | MFA_REQUIRED = 60003, 120 | MFA_UNVERIFIED = 60004, 121 | MFA_INVALID_SECRET = 60005, 122 | MFA_INVALID_TICKET = 60006, 123 | MFA_INVALID_CODE = 60008, 124 | MFA_INVALID_SESSION = 60009, 125 | 126 | PHONE_NUMBER_UNABLE_TO_SEND = 70003, 127 | PHONE_VERIFICATION_REQUIRED = 70007, 128 | 129 | RELATIONSHIP_INCOMING_DISABLED = 80000, 130 | RELATIONSHIP_INCOMING_BLOCKED = 80001, 131 | RELATIONSHIP_INVALUD_USER_BOT = 80002, 132 | RELATIONSHIP_INVALID_SELF = 80003, 133 | RELATIONSHIP_INVALID_DISCORD_TAG = 80004, 134 | 135 | REACTION_BLOCKED = 90001, 136 | 137 | LISTING_ALREADY_JOINED = 120000, 138 | LISTING_TOO_MANY_MEMBERS = 120001, 139 | LISTING_JOIN_BLOCKED = 120002, 140 | 141 | RESOURCE_OVERLOADED = 130000, 142 | 143 | INVALID_LOTTIE = 170001, 144 | } 145 | 146 | export enum DiscordHeaders { 147 | AUDIT_LOG_REASON = 'x-audit-log-reason', 148 | DEBUG_OPTIONS = 'x-debug-options', 149 | FINGERPRINT = 'x-fingerprint', 150 | SUPER_PROPERTIES = 'x-super-properties', 151 | TRACK = 'x-track', 152 | } 153 | 154 | export enum RatelimitHeaders { 155 | BUCKET = 'x-ratelimit-bucket', 156 | GLOBAL = 'x-ratelimit-global', 157 | LIMIT = 'x-ratelimit-limit', 158 | PRECISION = 'x-ratelimit-precision', 159 | REMAINING = 'x-ratelimit-remaining', 160 | RESET = 'x-ratelimit-reset', 161 | RESET_AFTER = 'x-ratelimit-reset-after', 162 | RETRY_AFTER = 'retry-after', 163 | } 164 | 165 | export enum RatelimitPrecisionTypes { 166 | MILLISECOND = 'millisecond', 167 | SECOND = 'second', 168 | } 169 | 170 | export enum RestEvents { 171 | REQUEST = 'request', 172 | RESPONSE = 'response', 173 | } 174 | 175 | 176 | export const RATELIMIT_BUCKET_MAJOR_PARAMS = Object.freeze(['channelId', 'guildId', 'webhookId', 'webhookToken']); 177 | 178 | export const SPOILER_ATTACHMENT_PREFIX = 'SPOILER_'; 179 | 180 | // https://github.com/discordapp/discord-api-docs/issues/1092 181 | // add 200 ms leeway incase our clock is wrong or the request takes too long 182 | export const MESSAGE_DELETE_RATELIMIT_CHECK = ((10) * 1000) - 200; // 10 seconds 183 | export const MESSAGE_DELETE_RATELIMIT_CHECK_OLDER = ((2 * 7 * 24 * 60 * 60) * 1000) - 200; // 2 weeks 184 | -------------------------------------------------------------------------------- /src/endpoints.ts: -------------------------------------------------------------------------------- 1 | import { URLSearchParams } from 'url'; 2 | 3 | import { Tools } from 'detritus-utils'; 4 | 5 | import { 6 | ActivityActionTypes, 7 | ApiVersion, 8 | } from './constants'; 9 | import { RequestTypes } from './types'; 10 | 11 | 12 | export { replacePathParameters as formatRoute } from 'detritus-rest'; 13 | 14 | 15 | export enum Urls { 16 | BLOG = 'https://blog.discord.com/', 17 | CANARY = 'https://canary.discord.com/', 18 | CDN = 'https://cdn.discordapp.com/', 19 | FEEDBACK = 'https://feedback.discord.com/', 20 | GIFT = 'https://discord.gift/', 21 | INVITE = 'https://discord.gg/', 22 | MEDIA = 'https://media.discordapp.net/', 23 | ROUTER = 'https://router.discordapp.net/', 24 | STABLE = 'https://discord.com/', 25 | STABLE_OLD = 'https://discordapp.com/', 26 | STATUS = 'https://status.discord.com/', 27 | SUPPORT = 'https://support.discord.com/', 28 | SUPPORT_DEV = 'https://support-dev.discord.com/', 29 | TEMPLATE = 'https://discord.new/', 30 | } 31 | 32 | export const Assets = Tools.URIEncodeWrap({ 33 | URL: `${Urls.STABLE.slice(0, -1)}/assets`, 34 | 35 | DM_GROUP: 36 | '/f046e2247d730629309457e902d5c5b3.svg', 37 | 38 | ICON: (hash: string, format: string = 'png'): string => 39 | `/${hash}.${format}`, 40 | }); 41 | 42 | export const CDN = Tools.URIEncodeWrap({ 43 | URL: Urls.CDN.slice(0, -1), 44 | 45 | APP_ASSET: (applicationId: string, hash: string, format: string = 'png'): string => 46 | `/app-assets/${applicationId}/${hash}.${format}`, 47 | APP_ASSET_ACHIEVEMENT: (applicationId: string, achievementId: string, hash: string): string => 48 | `/app-assets/${applicationId}/achievements/${achievementId}/icons/${hash}`, 49 | APP_ASSET_STORE: (applicationId: string, assetId: string, format: string = 'png'): string => 50 | `/app-assets/${applicationId}/store/${assetId}.${format}`, 51 | APP_ICON: (applicationId: string, hash: string, format: string = 'png'): string => 52 | `/app-icons/${applicationId}/${hash}.${format}`, 53 | APPLICATION_BACKGROUND: (applicationId: string): string => 54 | `/store-directory-assets/applications/${applicationId}/hero-background.jpg`, 55 | APPLICATION_TRAILER: (applicationId: string): string => 56 | `/store-directory-assets/applications/${applicationId}/trailer.mp4`, 57 | AVATAR: (userId: string, hash: string, format: string = 'png'): string => 58 | `/avatars/${userId}/${hash}.${format}`, 59 | AVATAR_DEFAULT: (discriminator: number | string): string => 60 | `/embed/avatars/${+(discriminator) % 5}.png`, 61 | BANNER: (id: string, hash: string, format: string = 'png'): string => 62 | `/banners/${id}/${hash}.${format}`, 63 | CHANNEL_ICON: (channelId: string, hash: string, format: string = 'png'): string => 64 | `/channel-icons/${channelId}/${hash}.${format}`, 65 | EMOJI: (emojiId: string, format: string = 'png'): string => 66 | `/emojis/${emojiId}.${format}`, 67 | GUILD_ICON: (guildId: string, hash: string, format: string = 'png'): string => 68 | `/icons/${guildId}/${hash}.${format}`, 69 | GUILD_SPLASH: (guildId: string, hash: string, format: string = 'png'): string => 70 | `/splashes/${guildId}/${hash}.${format}`, 71 | GUILD_USER_AVATAR: (guildId: string, userId: string, hash: string, format: string = 'png') => 72 | `/guilds/${guildId}/users/${userId}/avatars/${hash}.${format}`, 73 | STICKER: (stickerId: string, format: string = 'png'): string => 74 | `/stickers/${stickerId}.${format}`, 75 | STICKER_HASH: (stickerId: string, hash: string, format: string = 'png'): string => 76 | `/stickers/${stickerId}/${hash}.${format}`, 77 | TEAM_ICON: (teamId: string, hash: string, format: string = 'png'): string => 78 | `/team-icons/${teamId}/${hash}.${format}`, 79 | 80 | CUSTOM_SPOTIFY: (hash: string): string => 81 | `https://i.scdn.co/image/${hash}`, 82 | CUSTOM_TWITCH: (name: string, width: number, height: number): string => 83 | `https://static-cdn.jtvnw.net/previews-ttv/live_user_${name}-${width}x${height}.jpg`, 84 | CUSTOM_YOUTUBE: (videoId: string): string => 85 | `https://img.youtube.com/vi/${videoId}/default.jpg`, 86 | }); 87 | 88 | export const ConnectionUrls = Tools.URIEncodeWrap({ 89 | FACEBOOK: (id: string): string => 90 | `https://www.facebook.com/${id}`, 91 | REDDIT: (name: string): string => 92 | `https://www.reddit.com/u/${name}`, 93 | SKYPE: (id: string): string => 94 | `skype:${id}?userinfo`, 95 | SPOTIFY: (id: string): string => 96 | `https://open.spotify.com/user/${id}`, 97 | STEAM: (id: string): string => 98 | `https://steamcommunity.com/profiles/${id}`, 99 | TWITCH: (name: string): string => 100 | `https://www.twitch.tv/${name}`, 101 | TWITTER: (name: string): string => 102 | `https://twitter.com/${name}`, 103 | YOUTUBE: (id: string): string => 104 | `https://www.youtube.com/channel/${id}`, 105 | }); 106 | 107 | export const EmbedUrls = Tools.URIEncodeWrap({ 108 | YOUTUBE: (videoId: string): string => 109 | `https://www.youtube.com/embed/${videoId}?rel=0&showinfo=0&controls=1&origin=https://discordapp.com`, 110 | }); 111 | 112 | export const Gift = Tools.URIEncodeWrap({ 113 | LONG: (code: string): string => 114 | `${Urls.STABLE.slice(0, -1)}/gifts/${code}`, 115 | SHORT: (code: string): string => 116 | `${Urls.GIFT.slice(0, -1)}/${code}`, 117 | }); 118 | 119 | export const Invite = Tools.URIEncodeWrap({ 120 | LONG: (code: string): string => 121 | `${Urls.STABLE.slice(0, -1)}/invite/${code}`, 122 | SHORT: (code: string): string => 123 | `${Urls.INVITE.slice(0, -1)}/${code}`, 124 | }); 125 | 126 | export const Routes = Tools.URIEncodeWrap({ 127 | URL: Urls.STABLE.slice(0, -1), 128 | INDEX: 129 | '/', 130 | INDEX_WORD: 131 | '/index', 132 | INDEX_BUCKET: (bucketId: string): string => 133 | `/index/${bucketId}`, 134 | 404: 135 | '/404', 136 | APP: 137 | '/app', 138 | ACKNOWLEDGEMENTS: 139 | '/acknowledgements', 140 | ACTIVITY: 141 | '/activity', 142 | APPLICATION_LIBRARY: 143 | '/library', 144 | APPLICATION_LIBRARY_INVENTORY: 145 | '/library/inventory', 146 | APPLICATION_LIBRARY_ACTION: (gameId: string, action: string): string => 147 | `/library/${gameId}/${action}`, 148 | APPLICATION_STORE: 149 | '/store', 150 | APPLICATION_STORE_BROWSE: 151 | '/store/browse', 152 | APPLICATION_STORE_BROWSE_SORT: (sort: string): string => 153 | `/store/browse?genre=all&sort=${sort}`, 154 | APPLICATION_STORE_LISTING_APPLICATION: (applicationId: string, slug?: string): string => 155 | `/store/applications/${applicationId}` + ((slug) ? `/${slug}` : ''), 156 | APPLICATION_STORE_LISTING_SKU: (skuId: string, slug?: string): string => 157 | `/store/skus/${skuId}` + ((slug) ? `/${slug}` : ''), 158 | AUTHORIZE_IP: 159 | '/authorize-ip', 160 | BILLING_BRAINTREE_POPUP_BRIDGE_CALLBACK: 161 | '/billing/braintree/popup-bridge/callback', 162 | BILLING_GUILD_SUBSCRIPTIONS_PURCHASE: 163 | '/billing/guild-subscriptions/purchase', 164 | BILLING_PAYMENTS: 165 | '/billing/payments', 166 | BILLING_PAYMENT_SOURCES_CREATE: 167 | '/billing/payment-sources/create', 168 | BILLING_PREMIUM: 169 | '/billing/premium', 170 | BILLING_PREMIUM_SUBSCRIBE: 171 | '/billing/premium/subscribe', 172 | BILLING_PREMIUM_SWITCH_PLAN: 173 | '/billing/premium/switch-plan', 174 | BRANDING: 175 | '/branding', 176 | CHANGELOGS: 177 | '/settings/changelogs', 178 | CHANGELOGS_DATE: (date: string): string => 179 | `/settings/changelogs/${date}`, 180 | CHANNEL: (guildId: string | null, channelId: string): string => 181 | `/channels/${guildId || '@me'}/${channelId}`, 182 | COMPANY: 183 | '/company', 184 | CONNECTIONS: (platform: string): string => 185 | `/connections/${platform}`, 186 | CONNECTIONS_XBOX_EDU: 187 | '/connections/xbox/intro', 188 | CONNECTIONS_XBOX_PIN: 189 | '/connections/xbox/pin', 190 | DEV_NEWSLETTER: 191 | '/dev-newsletter', 192 | DISABLE_EMAIL_NOTIFICATIONS: 193 | '/disable-email-notifications', 194 | DOWNLOAD: 195 | '/download', 196 | FRIENDS: 197 | '/channels/@me', 198 | GIFT_CODE: (code: string): string => 199 | `/gifts/${code}`, 200 | GIFT_CODE_LOGIN: (code: string): string => 201 | `/gifts/${code}/login`, 202 | GUIDELINES: 203 | '/guidelines', 204 | GUILD: (guildId: string): string => 205 | `/channels/${guildId || '@me'}`, 206 | GUILD_CREATE: 207 | '/guilds/create', 208 | GUILD_DISCOVERY: 209 | '/guild-discovery', 210 | HANDOFF: 211 | '/handoff', 212 | HYPESQUAD: 213 | '/hypesquad', 214 | HYPESQUAD_RIOT: 215 | '/hypesquad-riot', 216 | INVITE: (code: string): string => 217 | `/invite/${code}`, 218 | INVITE_PROXY: (channelId: string): string => 219 | `/invite-proxy/${channelId}`, 220 | JOBS: 221 | '/jobs', 222 | JOB: (jobId: string) => 223 | `/jobs/${jobId}`, 224 | LICENSES: 225 | '/licenses', 226 | LOGIN: 227 | '/login', 228 | LOGIN_HANDOFF: 229 | '/login/handoff', 230 | LOGIN_REDIRECT_TO: (redirectTo: string) => 231 | `/login?redirect_to=${redirectTo}`, 232 | ME: 233 | '/channels/@me', 234 | MESSAGE: (guildId: string | null, channelId: string, messageId: string): string => 235 | `/channels/${guildId || '@me'}/${channelId}/${messageId}`, 236 | NEWSLETTER: 237 | '/newsletter', 238 | NITRO: 239 | '/nitro', 240 | OAUTH2_AUTHORIZE: 241 | '/oauth2/authorize', 242 | OAUTH2_AUTHORIZED: 243 | '/oauth2/authorized', 244 | OAUTH2_ERROR: 245 | '/oauth2/error', 246 | OAUTH2_WHITELIST_ACCEPT: 247 | '/oauth2/whitelist/accept', 248 | OPEN_SOURCE: 249 | '/open-source', 250 | OVERLAY: (buildId: string, port: number): string => 251 | `/overlay?build_id=${buildId}&rpc=${port}`, 252 | PARTNERS: 253 | '/partners', 254 | POPOUT_WINDOW: 255 | '/popout', 256 | PRIVACY: 257 | '/privacy', 258 | PRIVACY_2017: 259 | '/privacy-2017', 260 | PROMOTIONS_XBOX_GAME_PASS_REDEEM: (token: string) => 261 | `/promotions/xbox-game-pass/redeem/${token}`, 262 | REGISTER: 263 | '/register', 264 | REGISTER_REDIRECT_TO: (redirectTo: string) => 265 | `/register?redirect_to=${redirectTo}`, 266 | RESET: 267 | '/reset', 268 | RICH_PRESENCE: 269 | '/rich-presence', 270 | SECURITY: 271 | '/security', 272 | SELL_YOUR_GAME: 273 | '/sell-your-game', 274 | SELL_YOUR_GAMES: 275 | '/sell-your-games', 276 | SETTINGS: (section: string): string => 277 | `/settings/${section}`, 278 | SETTINGS_HYPESQUAD_ONLINE: 279 | '/settings/hypesquad-online', 280 | SETTINGS_SUB: (section: string, subsection: string) => 281 | `/settings/${section}/${subsection}`, 282 | STORE_BROWSE: 283 | '/store/browse', 284 | STORE_BROWSE_NITRO: 285 | '/store/browse?type=nitro', 286 | STORE_SKU: (skuId: string) => 287 | `/store/skus/${skuId}`, 288 | STORE_SKU_STORE_LISTING_ID: (skuId: string, storeListingId: string) => 289 | `/store/skus/${skuId}?store_listing_id=${storeListingId}`, 290 | STORE_TERMS: 291 | '/store-terms', 292 | STREAMKIT: 293 | '/streamkit', 294 | TEMPLATE: (templateId: string) => 295 | `/template/${templateId}`, 296 | TEMPLATE_LOGIN: (templateId: string) => 297 | `/template/${templateId}/login`, 298 | TERMS: 299 | '/terms', 300 | USER: (userId: string): string => 301 | `/users/${userId}`, 302 | VERIFICATION: 303 | '/verification', 304 | VERIFY: 305 | '/verify', 306 | WARFRAME: 307 | '/warframe', 308 | WELCOME: (guildId: string, channelId: string, type: number | string): string => 309 | `/welcome/${guildId}/${channelId}/${type}`, 310 | WIDGET: 311 | '/widget', 312 | XBOX_OFFER: 313 | '/discord-xbox-offer-2019', 314 | }); 315 | 316 | export const Template = Tools.URIEncodeWrap({ 317 | LONG: (code: string): string => 318 | `${Urls.STABLE.slice(0, -1)}/template/${code}`, 319 | SHORT: (code: string): string => 320 | `${Urls.TEMPLATE.slice(0, -1)}/${code}`, 321 | }); 322 | 323 | 324 | export const RoutesQuery = Object.freeze({ 325 | INVITE: (code: string, options: RequestTypes.RouteInvite = {}) => { 326 | const query = new URLSearchParams(); 327 | if (options.username) { 328 | query.set('username', options.username); 329 | } 330 | return `${Routes.INVITE(code)}?${query}`; 331 | }, 332 | WIDGET: (guildId: string, options: RequestTypes.RouteWidget = {}) => { 333 | const query = new URLSearchParams({id: guildId}); 334 | if (options.theme) { 335 | query.append('theme', options.theme); 336 | } 337 | if (options.username) { 338 | query.append('username', options.username); 339 | } 340 | return `${Routes.WIDGET}?${query}`; 341 | }, 342 | }); 343 | 344 | export const Api = Object.freeze({ 345 | URL_STABLE: Urls.STABLE.slice(0, -1), 346 | URL_CANARY: Urls.CANARY.slice(0, -1), 347 | PATH: `/api/v${ApiVersion}`, 348 | VERSION: ApiVersion, 349 | 350 | ACTIVITIES: 351 | '/activities', 352 | ACTIVITIES_APPLICATION_JOIN_TICKET: 353 | '/activities/applications/:applicationId/:ticketId/join-ticket', 354 | ACTIVITIES_STATISTICS_APPLICATION: 355 | '/activities/statistics/applications/:applicationId', 356 | 357 | APPLICATION_NEWS: 358 | '/application-news', 359 | APPLICATION_NEWS_ID: 360 | '/application-news/:newsId', 361 | 362 | APPLICATIONS: 363 | '/applications', 364 | APPLICATIONS_BOTS_COMMANDS: 365 | '/applications/bots/:applicationId/commands', 366 | APPLICATIONS_DETECTABLE: 367 | '/applications/detectable', 368 | APPLICATIONS_PUBLIC: 369 | '/applications/public', 370 | APPLICATIONS_TRENDING_GLOBAL: 371 | '/applications/trending/global', 372 | APPLICATION: 373 | '/applications/:applicationId', 374 | APPLICATION_BRANCHES: 375 | '/applications/:applicationId/branches', 376 | APPLICATION_BRANCH_BUILDS: 377 | '/applications/:applicationId/branches/:branchId/builds', 378 | APPLICATION_BRANCH_BUILDS_LIVE: 379 | '/applications/:applicationId/branches/:branchId/builds/live', 380 | APPLICATION_BRANCH_BUILD_PUBLISH: 381 | '/applications/:applicationId/branches/:branchId/builds/:buildId/publish', 382 | APPLICATION_BRANCH_BUILD_SIZE: 383 | '/applications/:applicationId/branches/:branchId/builds/:buildId/size', 384 | APPLICATION_BRANCH_STORAGE: 385 | '/applications/:applicationId/branches/:branchId/storage', 386 | APPLICATION_COMMANDS: 387 | '/applications/:applicationId/commands', 388 | APPLICATION_COMMAND: 389 | '/applications/:applicationId/commands/:commandId', 390 | APPLICATION_GIFT_CODE_BATCHES: 391 | '/applications/:applicationId/gift-code-batches', 392 | APPLICATION_GIFT_CODE_BATCHES_CSV_DOWNLOAD: 393 | '/applications/:applicationId/gift-code-batches/:batchId', 394 | APPLICATION_GUILD_COMMANDS: 395 | '/applications/:applicationId/guilds/:guildId/commands', 396 | APPLICATION_GUILD_COMMANDS_PERMISSIONS: 397 | '/applications/:applicationId/guilds/:guildId/commands/permissions', 398 | APPLICATION_GUILD_COMMAND: 399 | '/applications/:applicationId/guilds/:guildId/commands/:commandId', 400 | APPLICATION_GUILD_COMMAND_PERMISSIONS: 401 | '/applications/:applicationId/guilds/:guildId/commands/:commandId/permissions', 402 | APPLICATION_ICON: 403 | '/applications/:applicationId/app-icons/:hash.png', 404 | APPLICATION_MANIFEST_LABELS: 405 | '/applications/:applicationId/manifest-labels', 406 | APPLICATION_PURCHASE: 407 | '/applications/:applicationId/purchase', 408 | APPLICATION_SKUS: 409 | '/applications/:applicationId/skus', 410 | 411 | // these ones are weird lmao 412 | APPLICATION_ANALYTICS_ACQUISITIONS_ACQUIRERS: 413 | '/application/:applicationId/analytics/acquisitions/acquirers', 414 | APPLICATION_ANALYTICS_ACQUISITIONS_EXTERNAL: 415 | '/application/:applicationId/analytics/acquisitions/external', 416 | APPLICATION_ANALYTICS_ACQUISITIONS_FUNNEL: 417 | '/application/:applicationId/analytics/acquisitions/funnel', 418 | APPLICATION_ANALYTICS_ACQUISITIONS_IMPRESSIONS: 419 | '/application/:applicationId/analytics/acquisitions/impressions', 420 | APPLICATION_ANALYTICS_ACQUISITIONS_STORE_LISTING_VIEWS: 421 | '/application/:applicationId/analytics/acquisitions/store-listing-views', 422 | APPLICATION_ANALYTICS_ACQUISITIONS_UTM: 423 | '/application/:applicationId/analytics/acquisitions/utm', 424 | APPLICATION_ANALYTICS_ACTIVATIONS_FUNNEL: 425 | '/application/:applicationId/analytics/activations/funnel', 426 | APPLICATION_ANALYTICS_ACTIVATIONS_INSTALLATIONS: 427 | '/application/:applicationId/analytics/activations/installations', 428 | APPLICATION_ANALYTICS_ACTIVATIONS_NEW_PLAYERS: 429 | '/application/:applicationId/analytics/activations/new-players', 430 | APPLICATION_ANALYTICS_ACTIVATIONS_REACTIVATED_PLAYERS: 431 | '/application/:applicationId/analytics/activations/reactivated-players', 432 | APPLICATION_ANALYTICS_ENGAGEMENT_ACTIVE_PLAYERS: 433 | '/application/:applicationId/analytics/engagement/active-players', 434 | APPLICATION_ANALYTICS_ENGAGEMENT_PLAYER_RETENTION: 435 | '/application/:applicationId/analytics/engagement/player-retention', 436 | APPLICATION_ANALYTICS_REVENUE: 437 | '/application/:applicationId/analytics/revenue', 438 | APPLICATION_ANALYTICS_STATUS: 439 | '/application/:applicationId/analytics/status', 440 | APPLICATION_ANALYTICS_UNITS: 441 | '/application/:applicationId/analytics/units', 442 | 443 | AUTH_AUTHORIZE_IP: 444 | '/auth/authorize-ip', 445 | AUTH_CONSENT_REQUIRED: 446 | '/auth/consent-required', 447 | AUTH_HANDOFF: 448 | '/auth/handoff', 449 | AUTH_HANDOFF_EXCHANGE: 450 | '/auth/handoff/exchange', 451 | AUTH_LOGIN: 452 | '/auth/login', 453 | AUTH_LOGOUT: 454 | '/auth/logout', 455 | AUTH_MFA_SMS: 456 | '/auth/mfa/sms', 457 | AUTH_MFA_SMS_SEND: 458 | '/auth/mfa/sms/send', 459 | AUTH_MFA_TOTP: 460 | '/auth/mfa/totp', 461 | AUTH_PASSWORD_FORGOT: 462 | '/auth/forgot', 463 | AUTH_PASSWORD_RESET: 464 | '/auth/reset', 465 | AUTH_REGISTER: 466 | '/auth/register', 467 | AUTH_VERIFY: 468 | '/auth/verify', 469 | AUTH_VERIFY_RESEND: 470 | '/auth/verify/resend', 471 | 472 | BILLING_APPLE_RECEIPT: 473 | '/billing/apple/apply-receipt', 474 | BILLING_BRAINTREE_POPUP_BRIDGE: 475 | '/billing/braintree/popup-bridge', 476 | BILLING_BRAINTREE_POPUP_BRIDGE_CALLBACK: 477 | '/billing/braintree/popup-bridge/callback', 478 | BILLING_BRAINTREE_POPUP_BRIDGE_CALLBACK_STATE: 479 | '/billing/braintree/popup-bridge/callback/:state/', 480 | 481 | BRANCHES: 482 | '/branches', 483 | 484 | CHANNELS: 485 | '/channels', 486 | CHANNEL: 487 | '/channels/:channelId', 488 | CHANNEL_CALL: 489 | '/channels/:channelId/call', 490 | CHANNEL_CALL_RING: 491 | '/channels/:channelId/call/ring', 492 | CHANNEL_CALL_STOP_RINGING: 493 | '/channels/:channelId/call/stop-ringing', 494 | CHANNEL_FOLLOWER_MESSAGE_STATS: 495 | '/channels/:channelId/follower-message-stats', 496 | CHANNEL_FOLLOWER_STATS: 497 | '/channels/:channelId/follower-stats', 498 | CHANNEL_FOLLOWERS: 499 | '/channels/:channelId/followers', 500 | CHANNEL_ICON: 501 | '/channels/:channelId/icons/:hash.jgp', 502 | CHANNEL_INVITES: 503 | '/channels/:channelId/invites', 504 | CHANNEL_MESSAGES: 505 | '/channels/:channelId/messages', 506 | CHANNEL_MESSAGES_ACK: 507 | '/channels/:channelId/messages/ack', 508 | CHANNEL_MESSAGES_BULK_DELETE: 509 | '/channels/:channelId/messages/bulk-delete', 510 | CHANNEL_MESSAGES_SEARCH: 511 | '/channels/:channelId/messages/search', 512 | CHANNEL_MESSAGE: 513 | '/channels/:channelId/messages/:messageId', 514 | CHANNEL_MESSAGE_ACK: 515 | '/channels/:channelId/messages/:messageId/ack', 516 | CHANNEL_MESSAGE_CROSSPOST: 517 | '/channels/:channelId/messages/:messageId/crosspost', 518 | CHANNEL_MESSAGE_REACTIONS: 519 | '/channels/:channelId/messages/:messageId/reactions', 520 | CHANNEL_MESSAGE_REACTION: 521 | '/channels/:channelId/messages/:messageId/reactions/:emoji', 522 | CHANNEL_MESSAGE_REACTION_USER: 523 | '/channels/:channelId/messages/:messageId/reactions/:emoji/:userId', 524 | CHANNEL_MESSAGE_THREADS: 525 | '/channels/:channelId/messages/:messageId/threads', 526 | CHANNEL_PERMISSIONS: 527 | '/channels/:channelId/permissions', 528 | CHANNEL_PERMISSION: 529 | '/channels/:channelId/permissions/:overwriteId', 530 | CHANNEL_PINS: 531 | '/channels/:channelId/pins', 532 | CHANNEL_PINS_ACK: 533 | '/channels/:channelId/pins/ack', 534 | CHANNEL_PIN: 535 | '/channels/:channelId/pins/:messageId', 536 | CHANNEL_RECIPIENTS: 537 | '/channels/:channelId/recipients', 538 | CHANNEL_RECIPIENT: 539 | '/channels/:channelId/recipients/:userId', 540 | CHANNEL_STORE_LISTING: 541 | '/channels/:channelId/store-listing', 542 | CHANNEL_STORE_LISTING_ENTITLEMENT_GRANT: 543 | '/channels/:channelId/store-listing/entitlement-grant', 544 | CHANNEL_STORE_LISTINGS_SKU: 545 | '/channels/:channelId/store-listings/:skuId', 546 | CHANNEL_THREADS: 547 | '/channels/:channelId/threads', 548 | CHANNEL_THREADS_ACTIVE: 549 | '/channels/:channelId/threads/active', 550 | CHANNEL_THREADS_ARCHIVED_PRIVATE: 551 | '/channels/:channelId/threads/archived/private', 552 | CHANNEL_THREADS_ARCHIVED_PUBLIC: 553 | '/channels/:channelId/threads/archived/public', 554 | CHANNEL_THREAD_MEMBERS: 555 | '/channels/:channelId/thread-members', 556 | CHANNEL_THREAD_MEMBER: 557 | '/channels/:channelId/thread-members/:userId', 558 | CHANNEL_THREAD_MEMBER_ME: 559 | '/channels/:channelId/thread-members/@me', 560 | CHANNEL_TYPING: 561 | '/channels/:channelId/typing', 562 | CHANNEL_USER_THREADS_ARCHIVED_PRIVATE: 563 | '/channels/:channelId/users/:userId/threads/archived/private', 564 | CHANNEL_WEBHOOKS: 565 | '/channels/:channelId/webhooks', 566 | 567 | COMPANIES: 568 | '/companies', 569 | COMPANY: 570 | '/companies/:companyId', 571 | 572 | CONNECTION_AUTHORIZE: 573 | '/connections/:platform/authorize', 574 | CONNECTION_AUTHORIZE_CONTINUATION: 575 | '/connections/:platform/authorize?continuation=true', 576 | CONNECTION_CALLBACK: 577 | '/connections/:platform/callback', 578 | CONNECTION_CALLBACK_CONTINUATION: 579 | '/connections/:platform/callback-continuation', 580 | CONNECTION_CALLBACK_CONTINUATION_PIN: 581 | '/connections/:platform/callback-continuation/:pin', 582 | 583 | DISCOVERABLE_GUILDS: 584 | '/discoverable-guilds', 585 | 586 | DOWNLOAD_EMAIL: 587 | '/download/email', // disabled 588 | DOWNLOAD_SMS: 589 | '/download/sms', 590 | 591 | EMOJI: 592 | '/emojis/:emojiId.:format', 593 | EMOJI_GUILD: 594 | '/emojis/:emojiId/guild', 595 | 596 | ENTITLEMENTS_GIFT_CODE: 597 | '/entitlements/gift-codes/:code', 598 | ENTITLEMENTS_GIFT_CODE_REDEEM: 599 | '/entitlements/gift-codes/:code/redeem', 600 | 601 | EXPERIMENTS: 602 | '/experiments', 603 | 604 | FRIEND_SUGGESTIONS: 605 | '/friend-suggestions', 606 | FRIEND_SUGGESTIONS_ACCEPT_MUTUAL_CONTACTS: 607 | '/friend-suggestions/accept-mutual-contacts', 608 | FRIEND_SUGGESTIONS_SYNC: 609 | '/friend-suggestions/sync', 610 | FRIEND_SUGGESTION: 611 | '/friend-suggestions/:userId', 612 | 613 | GAME_NEWS: 614 | '/game-news', 615 | GAME_NEWS_ID: 616 | '/game-news?game_ids=:gameIds', 617 | 618 | GATEWAY: 619 | '/gateway', 620 | GATEWAY_BOT: 621 | '/gateway/bot', 622 | 623 | GIFS_SEARCH: 624 | '/gifs/search', 625 | GIFS_SELECT: 626 | '/gifs/select', 627 | GIFS_SUGGEST: 628 | '/gifs/suggest', 629 | GIFS_TRENDING: 630 | '/gifs/trending', 631 | GIFS_TRENDING_GIFS: 632 | '/gifs/trending-gifs', 633 | 634 | GUILDS: 635 | '/guilds', 636 | GUILDS_DISCOVERY: 637 | '/guilds/discoverable', 638 | GUILDS_TEMPLATE: 639 | '/guilds/templates/:templateId', 640 | GUILD: 641 | '/guilds/:guildId', 642 | GUILD_ACK: 643 | '/guilds/:guildId/ack', 644 | GUILD_ANALYTICS_OVERVIEW: 645 | '/guilds/:guildId/analytics/overview', 646 | GUILD_APPLICATIONS: 647 | '/guilds/:guildId/applications', 648 | GUILD_AUDIT_LOGS: 649 | '/guilds/:guildId/audit-logs', 650 | GUILD_BANS: 651 | '/guilds/:guildId/bans', 652 | GUILD_BAN: 653 | '/guilds/:guildId/bans/:userId', 654 | GUILD_BANNER: 655 | '/guilds/:guildId/banners/:hash.jpg', 656 | GUILD_CHANNELS: 657 | '/guilds/:guildId/channels', 658 | GUILD_DELETE: 659 | '/guilds/:guildId/delete', 660 | GUILD_DISCOVERY_CATEGORIES: 661 | '/guilds/:guildId/discovery-categories', 662 | GUILD_DISCOVERY_CHECKLIST: 663 | '/guilds/:guildId/discovery-checklist', 664 | GUILD_DISCOVERY_METADATA: 665 | '/guilds/:guildId/discovery-metadata', 666 | GUILD_DISCOVERY_VALID_TERM: 667 | '/guilds/:guildId/valid-term', 668 | GUILD_EMBED: 669 | '/guilds/:guildId/embed', 670 | GUILD_EMBED_JSON: 671 | '/guilds/:guildId/embed.json', 672 | GUILD_EMBED_PNG: 673 | '/guilds/:guildId/embed.png', 674 | GUILD_EMOJIS: 675 | '/guilds/:guildId/emojis', 676 | GUILD_EMOJI: 677 | '/guilds/:guildId/emojis/:emojiId', 678 | GUILD_ICON: 679 | '/guilds/:guildId/icons/:hash.:format', 680 | GUILD_INTEGRATIONS: 681 | '/guilds/:guildId/integrations', 682 | GUILD_INTEGRATION: 683 | '/guilds/:guildId/integrations/:integrationId', 684 | GUILD_INTEGRATION_SYNC: 685 | '/guilds/:guildId/integrations/:integrationId/sync', 686 | GUILD_INVITES: 687 | '/guilds/:guildId/invites', 688 | GUILD_MEMBER_VERIFICATION: 689 | '/guilds/:guildId/member-verification', 690 | GUILD_JOIN: 691 | '/guilds/:guildId/members/@me', 692 | GUILD_MEMBERS: 693 | '/guilds/:guildId/members', 694 | GUILD_MEMBERS_SEARCH: 695 | '/guilds/:guildId/members/search', 696 | GUILD_MEMBER: 697 | '/guilds/:guildId/members/:userId', 698 | GUILD_MEMBER_NICK: 699 | '/guilds/:guildId/members/@me/nick', 700 | GUILD_MEMBER_ROLE: 701 | '/guilds/:guildId/members/:userId/roles/:roleId', 702 | GUILD_MFA: 703 | '/guilds/:guildId/mfa', 704 | GUILD_PREMIUM_SUBSCRIPTIONS: 705 | '/guilds/:guildId/premium/subscriptions', 706 | GUILD_PREMIUM_SUBSCRIPTION: 707 | '/guilds/:guildId/premium/subscriptions/:subscriptionId', 708 | GUILD_PREVIEW: 709 | '/guilds/:guildId/preview', 710 | GUILD_PRUNE: 711 | '/guilds/:guildId/prune', 712 | GUILD_REGIONS: 713 | '/guilds/:guildId/regions', 714 | GUILD_ROLES: 715 | '/guilds/:guildId/roles', 716 | GUILD_ROLE: 717 | '/guilds/:guildId/roles/:roleId', 718 | GUILD_SEARCH: 719 | '/guilds/:guildId/messages/search', 720 | GUILD_SPLASH: 721 | '/guilds/:guildId/splashes/:hash.jpg', 722 | GUILD_STICKERS: 723 | '/guilds/:guildId/stickers', 724 | GUILD_STICKER: 725 | '/guilds/:guildId/stickers/:stickerId', 726 | GUILD_TEMPLATES: 727 | '/guilds/:guildId/templates', 728 | GUILD_TEMPLATE: 729 | '/guilds/:guildId/templates/:templateId', 730 | GUILD_VANITY_URL: 731 | '/guilds/:guildId/vanity-url', 732 | GUILD_VOICE_STATE: 733 | '/guilds/:guildId/voice-states/:userId', 734 | GUILD_WEBHOOKS: 735 | '/guilds/:guildId/webhooks', 736 | GUILD_WIDGET: 737 | '/guilds/:guildId/widget', 738 | GUILD_WIDGET_JSON: 739 | '/guilds/:guildId/widget.json', 740 | GUILD_WIDGET_PNG: 741 | '/guilds/:guildId/widget.png', 742 | 743 | HYPESQUAD_APPLY: 744 | '/hypesquad/apply', 745 | HYPESQUAD_ONLINE: 746 | '/hypesquad/online', 747 | 748 | INTEGRATIONS: 749 | '/integrations', 750 | INTEGRATION: 751 | '/integrations/:integrationId', 752 | INTEGRATION_JOIN: 753 | '/integrations/:integrationId/join', 754 | INTEGRATION_SEARCH: 755 | '/integrations/:integrationId/search', 756 | 757 | INTERACTIONS: 758 | '/interactions', 759 | INTERACTION_CALLBACK: 760 | '/interactions/:interactionId/:token/callback', 761 | 762 | INVITE: 763 | '/invites/:code', 764 | 765 | JOBS: 766 | '/jobs/:jobId', 767 | 768 | LOBBIES: 769 | '/lobbies', 770 | LOBBIES_SEARCH: 771 | '/lobbies/search', 772 | LOBBY: 773 | '/lobbies/:lobbyId', 774 | LOBBY_MEMBER: 775 | '/lobbies/:lobbyId/members/:userId', 776 | LOBBY_SEND: 777 | '/lobbies/:lobbyId/send', 778 | 779 | ME: 780 | '/users/@me', 781 | ME_ACTIVITIES_STATISTICS: 782 | '/users/@me/activities/statistics/applications', 783 | ME_ACTIVITY_JOIN_INVITE: 784 | `/users/@me/sessions/:currentSessionId/activities/:applicationId/${ActivityActionTypes.JOIN_REQUEST}/:userId`, 785 | ME_AFFINITIES_GUILDS: 786 | '/users/@me/affinities/guilds', 787 | ME_AFFINITIES_USERS: 788 | '/users/@me/affinities/users', 789 | ME_AGREEMENTS: 790 | '/users/@me/agreements', 791 | ME_APPLICATION_achievementS: 792 | '/users/@me/applications/:applicationId/achievements', 793 | ME_APPLICATION_ENTITLEMENTS: 794 | '/users/@me/applications/:applicationId/entitlements', 795 | ME_APPLICATION_ENTITLEMENT_TICKET: 796 | '/users/@me/applications/:applicationId/entitlement-ticket', 797 | ME_APPLICATION_TICKET: 798 | '/users/@me/applications/:applicationId/ticket', 799 | ME_BILLING_INVOICES_PREVIEW: 800 | '/users/@me/billing/invoices/preview', 801 | ME_BILLING_PAYMENT_SOURCES: 802 | '/users/@me/billing/payment-sources', 803 | ME_BILLING_PAYMENT_SOURCE: 804 | '/users/@me/billing/payment-sources/:paymentSourceId', 805 | ME_BILLING_PAYMENTS: 806 | '/users/@me/billing/payments', 807 | ME_BILLING_PAYMENT_VOID: 808 | '/users/@me/billing/payments/:paymentId/void', 809 | ME_BILLING_STRIPE_SETUP_INTENT: 810 | '/users/@me/billing/stripe/setup-intents', 811 | ME_BILLING_STRIPE_PAYMENT_INTENTS_PAYMENT: 812 | '/users/@me/billing/stripe/payment-intents/payments/:paymentId', 813 | ME_BILLING_SUBSCRIPTIONS: 814 | '/users/@me/billing/subscriptions', 815 | ME_BILLING_SUBSCRIPTION: 816 | '/users/@me/billing/subscriptions/:subscriptionId', 817 | ME_BILLING_TRIAL_ELIGIBILITY: 818 | '/users/@me/billings/trials/:trialId/eligibility', 819 | ME_CAPTCHA_VERIFY: 820 | '/users/@me/captcha/verify', 821 | ME_CHANNELS: 822 | '/users/@me/channels', 823 | ME_CONNECTIONS: 824 | '/users/@me/connections', 825 | ME_CONNECTION: 826 | '/users/@me/connections/:platform/:accountId', 827 | ME_CONNECTION_ACCESS_TOKEN: 828 | '/users/@me/connections/:platform/:accountId/access-token', 829 | ME_CONNECTION_REDDIT_SUBREDDITS: 830 | '/users/@me/connections/reddit/:accountId/subreddits', 831 | ME_CONSENT: 832 | '/users/@me/consent', 833 | ME_DELETE_ACCOUNT: 834 | '/users/@me/delete', 835 | ME_DEVICES: 836 | '/users/@me/devices', 837 | ME_DISABLE_ACCOUNT: 838 | '/users/@me/disable', 839 | ME_ENTITLEMENTS_GIFTS: 840 | '/users/@me/entitlements/gifts', 841 | ME_ENTITLEMENTS_GIFT_CODES: 842 | '/users/@me/entitlements/gift-codes', 843 | ME_ENTITLEMENTS_GIFT_CODE: 844 | '/users/@me/entitlements/gift-codes/:code', 845 | ME_FEED_SETTINGS: 846 | '/users/@me/feed/settings', 847 | ME_FEED_UNSUBSCRIBED_USERS: 848 | '/users/@me/feed/unsubscribed_users', 849 | ME_GUILDS: 850 | '/users/@me/guilds', 851 | ME_GUILDS_PREMIUM_SUBSCRIPTIONS: 852 | '/users/@me/guilds/premium/subscriptions', 853 | ME_GUILDS_PREMIUM_SUBSCRIPTIONS_COOLDOWN: 854 | '/users/@me/guilds/premium/subscriptions/cooldown', 855 | ME_GUILDS_PREMIUM_SUBSCRIPTION_SLOTS: 856 | '/users/@me/guilds/premium/subscription-slots', 857 | ME_GUILDS_PREMIUM_SUBSCRIPTION_SLOT_CANCEL: 858 | '/users/@me/guilds/premium/subscription-slots/:subscriptionId/cancel', 859 | ME_GUILDS_PREMIUM_SUBSCRIPTION_SLOT_UNCANCEL: 860 | '/users/@me/guilds/premium/subscription-slots/:subscriptionId/uncancel', 861 | ME_GUILD: 862 | '/users/@me/guilds/:guildId', 863 | ME_GUILD_SETTINGS: 864 | '/users/@me/guilds/:guildId/settings', 865 | ME_HARVEST: 866 | '/users/@me/harvest', 867 | ME_LIBRARY: 868 | '/users/@me/library', 869 | ME_LIBRARY_APPLICATION: 870 | '/users/@me/library/:applicationId', 871 | ME_LIBRARY_APPLICATION_BRANCH: 872 | '/users/@me/library/:applicationId/:branchId', 873 | ME_LIBRARY_APPLICATION_BRANCH_INSTALLED: 874 | '/users/@me/library/:applicationId/:branchId/installed', 875 | ME_MENTIONS: 876 | '/users/@me/mentions', 877 | ME_MENTION: 878 | '/users/@me/mentions/:messageId', 879 | ME_MFA_CODES: 880 | '/users/@me/mfa/codes', 881 | ME_MFA_SMS_DISABLE: 882 | '/users/@me/mfa/sms/disable', 883 | ME_MFA_SMS_ENABLE: 884 | '/users/@me/mfa/sms/enable', 885 | ME_MFA_TOTP_DISABLE: 886 | '/users/@me/mfa/totp/disable', 887 | ME_MFA_TOTP_ENABLE: 888 | '/users/@me/mfa/totp/enable', 889 | ME_NOTES: 890 | '/users/@me/notes', 891 | ME_NOTE: 892 | '/users/@me/notes/:userId', 893 | ME_PHONE: 894 | '/users/@me/phone', 895 | ME_PHONE_VERIFY: 896 | '/users/@me/phone/verify', 897 | ME_RELATIONSHIPS: 898 | '/users/@me/relationships', 899 | ME_RELATIONSHIP: 900 | '/users/@me/relationships/:userId', 901 | ME_REMOTE_AUTH: 902 | '/users/@me/remote-auth', 903 | ME_REMOTE_AUTH_CANCEL: 904 | '/users/@me/remote-auth/cancel', 905 | ME_REMOTE_AUTH_FINISH: 906 | '/users/@me/remote-auth/finish', 907 | ME_SETTINGS: 908 | '/users/@me/settings', 909 | ME_SETTINGS_GAME_NOTIFICATIONS: 910 | '/users/@me/settings/game-notifications', 911 | ME_SETTINGS_GAME_NOTIFICATIONS_OVERRIDES: 912 | '/users/@me/settings/game-notifications/overrides', 913 | ME_STICKER_PACKS: 914 | '/users/@me/sticker-packs', 915 | 916 | NATIVE_DEBUG_LOGS: 917 | '/native/debug-logs', 918 | 919 | NETWORKING_TOKEN: 920 | '/networking/token', 921 | 922 | OAUTH2_APPLICATIONS: 923 | '/oauth2/applications', 924 | OAUTH2_APPLICATION: 925 | '/oauth2/applications/:applicationId', 926 | OAUTH2_APPLICATION_ACHIEVEMENTS: 927 | '/oauth2/applications/:applicationId/achievements', 928 | OAUTH2_APPLICATION_ACHIEVEMENT: 929 | '/oauth2/applications/:applicationId/achievements/:achievementId', 930 | OAUTH2_APPLICATION_ACTIVATE_LICENSE: 931 | '/oauth2/applications/:applicationId/activate-license', 932 | OAUTH2_APPLICATION_APPROVALS: 933 | '/oauth2/applications/:applicationId/approvals', 934 | OAUTH2_APPLICATION_ASSETS: 935 | '/oauth2/applications/:applicationId/assets', 936 | OAUTH2_APPLICATION_ASSETS_ENABLE: 937 | '/oauth2/applications/:applicationId/assets/enable', 938 | OAUTH2_APPLICATION_ASSET: 939 | '/oauth2/applications/:applicationId/assets/:assetId', 940 | OAUTH2_APPLICATION_BOT: 941 | '/oauth2/applications/:applicationId/bot', 942 | OAUTH2_APPLICATION_BOT_RESET: 943 | '/oauth2/applications/:applicationId/bot/reset', 944 | OAUTH2_APPLICATION_DELETE: 945 | '/oauth2/applications/:applicationId/delete', 946 | OAUTH2_APPLICATION_RESET: 947 | '/oauth2/applications/:applicationId/reset', 948 | OAUTH2_APPLICATION_RICH_PRESENCE_APPROVAL_FORM: 949 | '/oauth2/applications/:applicationId/rich-presence/approval-form', 950 | OAUTH2_APPLICATION_RICH_PRESENCE_APPROVAL_FORM_SCREENSHOTS: 951 | '/oauth2/applications/:applicationId/rich-presence/approval-form/screenshots', 952 | OAUTH2_APPLICATION_RICH_PRESENCE_APPROVAL_FORM_SCREENSHOT: 953 | '/oauth2/applications/:applicationId/rich-presence/approval-form/screenshots/:screenshotId', 954 | OAUTH2_APPLICATION_RICH_PRESENCE_APPROVAL_FORM_SCREENSHOT_IMAGE: 955 | '/oauth2/applications/:applicationId/rich-presence/approval-form/screenshots/:screenshotId.jpg', 956 | OAUTH2_APPLICATION_RPC: 957 | '/oauth2/applications/:applicationId/rpc', 958 | OAUTH2_APPLICATION_RPC_APPLY: 959 | '/oauth2/applications/:applicationId/rpc/apply', 960 | OAUTH2_APPLICATION_RPC_ENABLE: 961 | '/oauth2/applications/:applicationId/rpc/enable', 962 | OAUTH2_APPLICATION_SKUS: 963 | '/oauth2/applications/:applicationId/skus', 964 | OAUTH2_APPLICATION_TRANSFER: 965 | '/oauth2/applications/:applicationId/transfer', 966 | OAUTH2_APPLICATION_WHITELIST: 967 | '/oauth2/applications/:applicationId/whitelist', 968 | OAUTH2_APPLICATION_WHITELIST_USER: 969 | '/oauth2/applications/:applicationId/whitelist/:userId', 970 | OAUTH2_AUTHORIZE: 971 | '/oauth2/authorize', 972 | OAUTH2_AUTHORIZE_WEBHOOK_CHANNELS: 973 | '/oauth2/authorize/webhook-channels', 974 | OAUTH2_ME: 975 | '/oauth2/@me', 976 | OAUTH2_TOKEN: 977 | '/oauth2/token', 978 | OAUTH2_TOKEN_REVOKE: 979 | '/oauth2/token/revoke', 980 | OAUTH2_TOKENS: 981 | '/oauth2/tokens', 982 | OAUTH2_TOKENS_SINGLE: 983 | '/oauth2/tokens/:tokenId', 984 | OAUTH2_TOKEN_RPC: 985 | '/oauth2/token/rpc', 986 | OAUTH2_WHITELIST_ACCEPT: 987 | '/oauth2/whitelist/accept', 988 | 989 | PARTNERS_APPLY: 990 | '/partners/apply', 991 | PARTNERS_CONNECTIONS: 992 | '/partners/connections', 993 | PARTNER_REQUIREMENTS: 994 | '/partners/:guildId/requirements', 995 | 996 | PROMOTIONS: 997 | '/promotions', 998 | PROMOTIONS_ACK: 999 | '/promotions/ack', 1000 | PROMOTIONS_FUNIMATION: 1001 | '/promotions/funimation', 1002 | PROMOTIONS_FUNIMATION_REDEEM: 1003 | '/promotions/funimation/redeem', 1004 | PROMOTIONS_XBOX_GAME_PASS: 1005 | '/promotions/xbox-game-pass', 1006 | PROMOTIONS_XBOX_GAME_PASS_REDEEM: 1007 | '/promotions/xbox-game-pass/redeem', 1008 | 1009 | READ_STATES_ACK_BULK: 1010 | '/read-states/ack-bulk', 1011 | 1012 | REPORT: 1013 | '/report', 1014 | 1015 | RTC_QUALITY_REPORT: 1016 | '/rtc/quality-report', 1017 | 1018 | SSO: 1019 | '/sso', 1020 | 1021 | STAGE_INSTANCES: 1022 | '/stage-instances', 1023 | STAGE_INSTANCE: 1024 | '/stage-instances/:channelId', 1025 | 1026 | STICKER_ASSET: 1027 | '/stickers/:stickerId/:assetId.:format', 1028 | 1029 | STICKER_PACKS_DIRECTORY: 1030 | '/sticker-packs/directory/:directoryId', 1031 | STICKER_PACK: 1032 | '/sticker-packs/:stickerPackId', 1033 | 1034 | STORE_APPLICATION_ASSETS: 1035 | '/store/applications/:applicationId/assets', 1036 | STORE_APPLICATION_ASSET: 1037 | '/store/applications/:applicationId/assets/:assetId', 1038 | STORE_APPLICATION_ASSET_IMAGE: 1039 | '/store/applications/:applicationId/assets/:assetId.:format', 1040 | STORE_DIRECTORY_LAYOUT: 1041 | '/store/directory-layouts/:layoutId', 1042 | STORE_DIRECTORY: 1043 | '/store/directory/:layoutId', 1044 | STORE_EULA: 1045 | '/store/eulas/:eulaId', 1046 | STORE_LISTINGS: 1047 | '/store/listings', 1048 | STORE_LISTING: 1049 | '/store/listings/:listingId', 1050 | STORE_PRICE_TIERS: 1051 | '/store/price-tiers', 1052 | STORE_PRICE_TIER: 1053 | '/store/price-tiers/:priceTier', 1054 | STORE_PUBLISHED_LISTINGS_APPLICATIONS: 1055 | '/store/published-listings/applications', 1056 | STORE_PUBLISHED_LISTINGS_APPLICATION: 1057 | '/store/published-listings/applications/:applicationId', 1058 | STORE_PUBLISHED_LISTINGS_SKUS: 1059 | '/store/published-listings/skus', 1060 | STORE_PUBLISHED_LISTINGS_SKU: 1061 | '/store/published-listings/skus/:skuId', 1062 | STORE_PUBLISHED_LISTINGS_SKU_JOIN_GUILD: 1063 | '/store/published-listings/skus/:skuId/guild/join', 1064 | STORE_PUBLISHED_LISTINGS_SKU_SUBSCRIPTION_PLANS: 1065 | '/store/published-listings/skus/:skuId/subscription-plans', 1066 | STORE_SKUS: 1067 | '/store/skus', 1068 | STORE_SKU: 1069 | '/store/skus/:skuId', 1070 | STORE_SKU_LISTINGS: 1071 | '/store/skus/:skuId/listings', 1072 | STORE_SKU_PURCHASE: 1073 | '/store/skus/:skuId/purchase', 1074 | 1075 | STREAM_NOTIFY: 1076 | '/streams/:streamKey/notify', 1077 | STREAM_PREVIEW: 1078 | '/streams/:streamKey/preview', 1079 | 1080 | TEAMS: 1081 | '/teams', 1082 | TEAMS_INVITE_ACCEPT: 1083 | '/teams/invite/accept', 1084 | TEAM: 1085 | '/teams/:teamId', 1086 | TEAM_APPLICATIONS: 1087 | '/teams/:teamId/applications', 1088 | TEAM_COMPANIES: 1089 | '/teams/:teamId/companies', 1090 | TEAM_DELETE: 1091 | '/teams/:teamId/delete', 1092 | TEAM_MEMBERS: 1093 | '/teams/:teamId/members', 1094 | TEAM_MEMBER: 1095 | '/teams/:teamId/members/:userId', 1096 | TEAM_PAYOUTS: 1097 | '/teams/:teamId/payouts', 1098 | TEAM_PAYOUTS_IFRAME: 1099 | '/teams/:teamId/payouts/onboarding', 1100 | 1101 | TEMPLATE_ICON: 1102 | '/templates/:templateId/icons/:hash.jpg', 1103 | 1104 | TRACK: 1105 | '/science', 1106 | 1107 | TUTORIAL: 1108 | '/tutorial', 1109 | TUTORIAL_INDICATORS: 1110 | '/tutorial/indicators', 1111 | TUTORIAL_INDICATORS_SUPPRESS: 1112 | '/tutorial/indicators/suppress', 1113 | TUTORIAL_INDICATOR: 1114 | '/tutorial/indicators/:indicatorId', 1115 | 1116 | UNVERIFIED_APPLICATIONS: 1117 | '/unverified-applications', 1118 | UNVERIFIED_APPLICATIONS_ICONS: 1119 | '/unverified-applications/icons', 1120 | 1121 | USERS: 1122 | '/users', 1123 | USERS_DISABLE_EMAIL_NOTIFICATIONS: 1124 | '/users/disable-email-notifications', 1125 | USER: 1126 | '/users/:userId', 1127 | USER_ACTIVITY_METADATA: 1128 | '/users/:userId/sessions/:sessionId/activities/:activityId/metadata', 1129 | USER_ACTIVITY_JOIN: 1130 | `/users/:userId/sessions/:sessionId/activities/:activityId/${ActivityActionTypes.JOIN}`, 1131 | USER_ACTIVITY_JOIN_REQUEST: 1132 | `/users/:userId/sessions/:sessionId/activities/:activityId/${ActivityActionTypes.JOIN_REQUEST}`, 1133 | USER_ACTIVITY_SPECTATE: 1134 | `/users/:userId/sessions/:sessionId/activities/:activityId/${ActivityActionTypes.SPECTATE}`, 1135 | USER_APPLICATION_ACHIEVEMENT: 1136 | '/users/:userId/applications/:applicationId/achievements/:achievementId', 1137 | USER_AVATAR: 1138 | '/users/:userId/avatars/:hash.jpg', 1139 | USER_CHANNELS: 1140 | '/users/:userId/channels', 1141 | USER_PROFILE: 1142 | '/users/:userId/profile', 1143 | USER_RELATIONSHIPS: 1144 | '/users/:userId/relationships', 1145 | 1146 | VERIFIED_SERVERS_APPLY: 1147 | '/verified-servers/apply', 1148 | VERIFIED_SERVERS_NEWSLETTER: 1149 | '/verified-servers/newsletter', 1150 | 1151 | VOICE_DEBUG_FILE: 1152 | '/voice/debug/file', 1153 | VOICE_ICE: 1154 | '/voice/ice', 1155 | VOICE_REGIONS: 1156 | '/voice/regions', 1157 | 1158 | WEBHOOK: 1159 | '/webhooks/:webhookId', 1160 | WEBHOOK_TOKEN: 1161 | '/webhooks/:webhookId/:webhookToken', 1162 | WEBHOOK_TOKEN_MESSAGE: 1163 | '/webhooks/:webhookId/:webhookToken/messages/:messageId', 1164 | WEBHOOK_TOKEN_GITHUB: 1165 | '/webhooks/:webhookId/:webhookToken/github', 1166 | WEBHOOK_TOKEN_SLACK: 1167 | '/webhooks/:webhookId/:webhookToken/slack', 1168 | }); 1169 | -------------------------------------------------------------------------------- /src/errors.ts: -------------------------------------------------------------------------------- 1 | import { Response } from 'detritus-rest'; 2 | 3 | class BaseError extends Error { 4 | 5 | } 6 | 7 | export class HTTPError extends BaseError { 8 | code: any; 9 | response: Response; 10 | 11 | constructor(response: Response, message?: string, code?: any) { 12 | let httpMessage = `HTTP Exception: ${response.statusCode}`; 13 | if (message) { 14 | httpMessage += ` (${message})`; 15 | } 16 | 17 | super(httpMessage); 18 | this.code = code; 19 | this.response = response; 20 | } 21 | } 22 | 23 | 24 | 25 | export interface DiscordHTTPValueErrorBody { 26 | code: string, 27 | message: string, 28 | } 29 | 30 | export interface DiscordHTTPValueError { 31 | _errors?: Array, 32 | [key: string]: DiscordHTTPValueError | Array | undefined, 33 | } 34 | 35 | export interface DiscordHTTPErrorOptions { 36 | code: number, 37 | errors?: DiscordHTTPValueError, 38 | message: string, 39 | } 40 | 41 | export class DiscordHTTPError extends HTTPError { 42 | code: number; 43 | errors?: DiscordHTTPValueError; 44 | raw: DiscordHTTPErrorOptions; 45 | 46 | constructor(response: Response, raw: DiscordHTTPErrorOptions) { 47 | super(response, raw.message, raw.code); 48 | this.code = raw.code; 49 | this.errors = raw.errors; 50 | this.raw = raw; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import * as Constants from './constants'; 2 | import * as Endpoints from './endpoints'; 3 | import * as Utils from './utils'; 4 | 5 | export { Constants, Endpoints, Utils }; 6 | export * from './client'; 7 | export * from './types'; 8 | -------------------------------------------------------------------------------- /src/request.ts: -------------------------------------------------------------------------------- 1 | import { URL } from 'url'; 2 | 3 | import { Request, Response } from 'detritus-rest'; 4 | import { ContentTypes, HTTPHeaders, HTTPMethods } from 'detritus-rest/lib/constants'; 5 | import { Snowflake } from 'detritus-utils'; 6 | 7 | import { Bucket } from './bucket'; 8 | import { Client } from './client'; 9 | import { 10 | RatelimitHeaders, 11 | RatelimitPrecisionTypes, 12 | RestEvents, 13 | MESSAGE_DELETE_RATELIMIT_CHECK, 14 | MESSAGE_DELETE_RATELIMIT_CHECK_OLDER, 15 | RATELIMIT_BUCKET_MAJOR_PARAMS, 16 | } from './constants'; 17 | import { Api } from './endpoints'; 18 | import { DiscordHTTPError, HTTPError } from './errors'; 19 | 20 | 21 | export interface RestRequestOptions { 22 | errorOnRatelimit?: boolean, 23 | errorOnRatelimitIfMoreThan?: number, 24 | skipRatelimitCheck?: boolean, 25 | } 26 | 27 | export class RestRequest { 28 | readonly bucketPath?: string; 29 | 30 | _bucketHash?: string; 31 | _bucketKey?: string; 32 | 33 | client: Client; 34 | errorOnRatelimit?: boolean; 35 | errorOnRatelimitIfMoreThan?: number; 36 | maxRetries: number; 37 | request: Request; 38 | retries: number; 39 | retryDelay: number; 40 | skipRatelimitCheck?: boolean; 41 | 42 | constructor( 43 | client: Client, 44 | request: Request, 45 | options: RestRequestOptions = {}, 46 | ) { 47 | this.client = client; 48 | this.request = request; 49 | 50 | if (this.shouldRatelimitCheck) { 51 | if (client.isBot) { 52 | request.headers.set(RatelimitHeaders.PRECISION, RatelimitPrecisionTypes.MILLISECOND); 53 | } 54 | 55 | if (request.route) { 56 | this.bucketPath = `${request.route.method}-${request.route.path}`; 57 | if (request.route.method === HTTPMethods.DELETE && request.route.path === Api.CHANNEL_MESSAGE) { 58 | if ('messageId' in request.route.params) { 59 | const difference = Date.now() - Snowflake.timestamp(request.route.params.messageId); 60 | if (MESSAGE_DELETE_RATELIMIT_CHECK_OLDER <= difference) { 61 | this.bucketPath = `${this.bucketPath}.${MESSAGE_DELETE_RATELIMIT_CHECK_OLDER}`; 62 | } else if (MESSAGE_DELETE_RATELIMIT_CHECK <= difference) { 63 | this.bucketPath = `${this.bucketPath}.${MESSAGE_DELETE_RATELIMIT_CHECK}`; 64 | } 65 | } 66 | } else if (request.route.method === HTTPMethods.PATCH && request.route.path === Api.CHANNEL) { 67 | // add custom bucketPaths for editing {name} and {topic} 68 | // https://github.com/discord/discord-api-docs/issues/2190 69 | } 70 | } 71 | } 72 | 73 | this.errorOnRatelimit = options.errorOnRatelimit; 74 | this.errorOnRatelimitIfMoreThan = options.errorOnRatelimitIfMoreThan; 75 | this.maxRetries = 5; 76 | this.retries = 0; 77 | this.retryDelay = 2000; 78 | this.skipRatelimitCheck = options.skipRatelimitCheck; 79 | } 80 | 81 | get bucket(): Bucket | null { 82 | if (this.bucketKey) { 83 | return this.client.buckets.get(this.bucketKey) || null; 84 | } 85 | return null; 86 | } 87 | 88 | get bucketHash(): null | string { 89 | if (this._bucketHash) { 90 | return this._bucketHash; 91 | } 92 | if (!this.skipRatelimitCheck && this.request.route && this.shouldRatelimitCheck) { 93 | const path = this.bucketPath as string; 94 | if (this.client.isBot) { 95 | if (this.client.routes.has(path)) { 96 | return this._bucketHash = this.client.routes.get(path) as string; 97 | } 98 | } else { 99 | return this._bucketHash = path; 100 | } 101 | } 102 | return null; 103 | } 104 | 105 | get bucketKey(): null | string { 106 | if (this._bucketKey) { 107 | return this._bucketKey; 108 | } 109 | if (this.request.route) { 110 | const bucketHash = this.bucketHash; 111 | if (bucketHash) { 112 | let major = ''; 113 | for (let param of RATELIMIT_BUCKET_MAJOR_PARAMS) { 114 | if (param in this.request.route.params) { 115 | major += this.request.route.params[param].trim(); 116 | } 117 | major += '-'; 118 | } 119 | return this._bucketKey = `${bucketHash}.${major.slice(0, -1)}`; 120 | } 121 | } 122 | return null; 123 | } 124 | 125 | get shouldRatelimitCheck(): boolean { 126 | return ( 127 | (this.client.restClient.baseUrl instanceof URL) && 128 | (this.client.restClient.baseUrl.host === this.request.parsedUrl.host) 129 | ); 130 | } 131 | 132 | sendRequest(): Promise { 133 | return new Promise((resolve, reject) => { 134 | if (this.shouldRatelimitCheck && !this.errorOnRatelimit) { 135 | if (this.client.globalBucket.locked) { 136 | return this.client.globalBucket.add({request: this, resolve, reject}); 137 | } 138 | 139 | const bucket = this.bucket; 140 | if (bucket) { 141 | if (bucket.locked) { 142 | return bucket.add({request: this, resolve, reject}); 143 | } 144 | if (bucket.ratelimit.remaining === 1) { 145 | const ratelimit = bucket.ratelimit; 146 | const diff = Math.min(0, ratelimit.resetAtLocal - Date.now()); 147 | if (diff && (!this.errorOnRatelimitIfMoreThan || diff <= this.errorOnRatelimitIfMoreThan)) { 148 | bucket.lock(diff); 149 | } 150 | } 151 | } 152 | } 153 | resolve(this.request.send()); 154 | }); 155 | } 156 | 157 | async send(): Promise { 158 | const response = await this.sendRequest(); 159 | this.client.emit(RestEvents.RESPONSE, {response, restRequest: this}); 160 | 161 | if (this.shouldRatelimitCheck) { 162 | let bucket: Bucket | null = null; 163 | 164 | if (this.request.route) { 165 | // reason for this check is just incase the request doesnt have one and we will still check the global ratelimit 166 | 167 | let shouldHaveBucket: boolean = false; 168 | if (this.client.isBot) { 169 | if (response.headers.has(RatelimitHeaders.BUCKET) && this.bucketPath) { 170 | this.client.routes.set(this.bucketPath, response.headers.get(RatelimitHeaders.BUCKET) as string); 171 | shouldHaveBucket = true; 172 | } else { 173 | // no ratelimit on this path 174 | } 175 | } else { 176 | // users dont get the above header 177 | shouldHaveBucket = true; 178 | } 179 | 180 | if (shouldHaveBucket && !this.skipRatelimitCheck) { 181 | bucket = this.bucket; 182 | if (!bucket) { 183 | bucket = new Bucket(this.bucketKey as string); 184 | this.client.buckets.insert(bucket); 185 | } 186 | } 187 | } 188 | 189 | if (bucket) { 190 | if (response.headers.has(RatelimitHeaders.LIMIT)) { 191 | bucket.setRatelimit( 192 | parseInt(response.headers.get(RatelimitHeaders.LIMIT) || ''), 193 | parseInt(response.headers.get(RatelimitHeaders.REMAINING) || ''), 194 | (parseFloat(response.headers.get(RatelimitHeaders.RESET) || '') || 0) * 1000, 195 | (parseFloat(response.headers.get(RatelimitHeaders.RESET_AFTER) || '') || 0) * 1000, 196 | ); 197 | } 198 | 199 | const ratelimit = bucket.ratelimit; 200 | if (ratelimit.remaining <= 0 && response.statusCode !== 429) { 201 | const diff = ratelimit.resetAfter; 202 | if (diff) { 203 | bucket.lock(diff); 204 | } 205 | } 206 | } 207 | 208 | if (response.statusCode === 429 && !this.errorOnRatelimit) { 209 | // ratelimited, retry 210 | let retryAfter = 0; 211 | if (response.headers.has(RatelimitHeaders.RESET_AFTER)) { 212 | retryAfter = (parseFloat(response.headers.get(RatelimitHeaders.RESET_AFTER) || '') || 0) * 1000; 213 | } else { 214 | retryAfter = (parseInt(response.headers.get(RatelimitHeaders.RETRY_AFTER) || '') || 0) * 1000; 215 | } 216 | 217 | if (!this.errorOnRatelimitIfMoreThan || retryAfter <= this.errorOnRatelimitIfMoreThan) { 218 | const isDiscordRatelimit = response.headers.has('via'); 219 | return new Promise(async (resolve, reject) => { 220 | const delayed = {request: this, resolve, reject}; 221 | 222 | const data = await response.json() as {global: boolean, retry_after: number}; 223 | if (this.client.isBot) { 224 | if (response.headers.get(RatelimitHeaders.GLOBAL) === 'true') { 225 | this.client.globalBucket.lock(retryAfter); 226 | this.client.globalBucket.add(delayed); 227 | return; 228 | } 229 | 230 | // incase they, for some reason, send us a differing body from the headers (happened cuz of channel edits with name/topic) 231 | // just error out since this is a fluke 232 | if ((data.retry_after * 1000) !== retryAfter) { 233 | return reject(new HTTPError(response)); 234 | } 235 | } else { 236 | if (isDiscordRatelimit) { 237 | // check json body since users dont get the above header 238 | if (data.global) { 239 | this.client.globalBucket.lock(retryAfter); 240 | this.client.globalBucket.add(delayed); 241 | return; 242 | } 243 | } 244 | } 245 | 246 | if (bucket) { 247 | bucket.ratelimit.remaining = 0; 248 | bucket.ratelimit.resetAfter = retryAfter; 249 | bucket.lock(retryAfter); 250 | bucket.add(delayed, true); 251 | return; 252 | } 253 | 254 | // unsure of what to do since we should've gotten global ratelimited 255 | return reject(new HTTPError(response)); 256 | }); 257 | } 258 | 259 | if (bucket && bucket.size) { 260 | this.client.buckets.resetExpire(bucket); 261 | } 262 | } 263 | } 264 | 265 | if (response.statusCode === 502 && this.maxRetries <= this.retries++) { 266 | return new Promise((resolve, reject) => { 267 | setTimeout(() => { 268 | this.request.send().then(resolve).catch(reject); 269 | }, this.retryDelay); 270 | return; 271 | }); 272 | } 273 | 274 | if (!response.ok) { 275 | let data: any; 276 | switch ((response.headers.get(HTTPHeaders.CONTENT_TYPE) || '').split(';').shift()) { 277 | case ContentTypes.APPLICATION_JSON: { 278 | data = await response.json(); 279 | }; break; 280 | case ContentTypes.TEXT_PLAIN: { 281 | data = await response.text(); 282 | }; break; 283 | default: { 284 | data = await response.buffer(); 285 | if (!data.length) { 286 | data = null; 287 | } 288 | }; 289 | } 290 | if (data && typeof(data) === 'object' && !Buffer.isBuffer(data)) { 291 | if ( 292 | (this.client.restClient.baseUrl instanceof URL) && 293 | (this.client.restClient.baseUrl.host === this.request.parsedUrl.host) 294 | ) { 295 | throw new DiscordHTTPError(response, data); 296 | } else { 297 | throw new HTTPError(response, data.message, data.code); 298 | } 299 | } else { 300 | throw new HTTPError(response, data); 301 | } 302 | } 303 | return response; 304 | } 305 | } 306 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import { Request, RequestFile, RequestOptions, Response, Route } from 'detritus-rest'; 2 | 3 | import { RestRequest } from './request'; 4 | 5 | 6 | export namespace RestClientEvents { 7 | export interface RequestPayload { 8 | request: Request, 9 | restRequest: RestRequest, 10 | } 11 | 12 | export interface ResponsePayload { 13 | response: Response, 14 | restRequest: RestRequest, 15 | } 16 | } 17 | 18 | export namespace RequestTypes { 19 | export interface File extends RequestFile { 20 | hasSpoiler?: boolean, 21 | } 22 | 23 | export interface Options extends RequestOptions { 24 | dataOnly?: boolean, 25 | errorOnRatelimit?: boolean, 26 | fingerprint?: string, 27 | skipRatelimitCheck?: boolean, 28 | token?: string, 29 | useAuth?: boolean, 30 | } 31 | 32 | export interface toJSON { 33 | toJSON: () => X, 34 | } 35 | 36 | 37 | /* Option Interfaces */ 38 | 39 | export interface AcceptTemplate { 40 | icon?: Buffer | string, 41 | name: string, 42 | } 43 | 44 | export interface ActivateOauth2ApplicationLicense { 45 | code?: string, 46 | guildId: string, 47 | } 48 | 49 | export interface AddConnection { 50 | name: string, 51 | friendSync?: boolean, 52 | } 53 | 54 | export interface AddGuildMember { 55 | accessToken: string, 56 | deaf?: boolean, 57 | mute?: boolean, 58 | nick?: string, 59 | roles?: Array, 60 | } 61 | 62 | export interface AddGuildMemberRole { 63 | reason?: string, 64 | } 65 | 66 | export interface AddTeamMember { 67 | discriminator: string, 68 | username: string, 69 | } 70 | 71 | export interface AddOauth2ApplicationWhitelistUser { 72 | branchIds?: Array, 73 | discriminator: string, 74 | username: string, 75 | } 76 | 77 | export interface AuthorizeIpAddress { 78 | token: string, 79 | } 80 | 81 | export interface BeginGuildPrune { 82 | computePruneCount?: boolean, 83 | days?: number, 84 | includeRoles?: Array, 85 | reason?: string, 86 | } 87 | 88 | export interface BulkOverwriteApplicationGuildCommandsPermission { 89 | id: string, 90 | permissions: Array, 91 | } 92 | 93 | export type BulkOverwriteApplicationGuildCommandsPermissions = Array; 94 | 95 | export interface ConnectionCallback { 96 | code: string, 97 | friendSync: boolean, 98 | fromContinuation: boolean, 99 | insecure?: boolean, 100 | openIdParams: object, 101 | state: string, 102 | } 103 | 104 | export interface CreateApplicationCommand { 105 | defaultPermission?: boolean, 106 | description: string, 107 | id?: string, 108 | name: string, 109 | options?: Array>, 110 | type?: number, 111 | } 112 | 113 | export interface CreateApplicationCommandData { 114 | default_permission?: boolean, 115 | description?: string, 116 | id?: string, 117 | name: string, 118 | options?: Array> 119 | type?: number, 120 | } 121 | 122 | export interface CreateApplicationCommandOption { 123 | choices?: Array<{name: string, value: string | number}>, 124 | description?: string, 125 | name: string, 126 | options?: Array>, 127 | required?: boolean, 128 | type: number, 129 | } 130 | 131 | export interface CreateApplicationGuildCommand extends CreateApplicationCommand { 132 | 133 | } 134 | 135 | export interface CreateApplicationGuildCommandData extends CreateApplicationCommandData { 136 | 137 | } 138 | 139 | export interface CreateApplicationNews { 140 | applicationId: string, 141 | channelId: string, 142 | description?: string, 143 | messageId: string, 144 | thumbnailOverride?: Buffer | string, 145 | title?: string, 146 | url?: string, 147 | } 148 | 149 | export interface CreateChannelInvite { 150 | maxAge?: number, 151 | maxUses?: number, 152 | targetApplicationId?: string, 153 | targetType?: number, 154 | targetUserId?: string, 155 | temporary?: boolean, 156 | unique?: boolean, 157 | } 158 | 159 | export interface CreateChannelMessageComponent { 160 | components?: Array>, 161 | customId?: string, 162 | disabled?: boolean, 163 | emoji?: RawEmojiPartial, 164 | label?: string, 165 | maxValues?: number, 166 | minValues?: number, 167 | options?: Array, 168 | placeholder?: string, 169 | style?: number, 170 | type: number, 171 | url?: string, 172 | } 173 | 174 | export interface CreateChannelMessageComponentSelectMenuOption { 175 | default?: boolean, 176 | description?: string, 177 | emoji?: RawEmojiPartial, 178 | label: string, 179 | value: string, 180 | } 181 | 182 | export interface CreateChannelMessageEmbed { 183 | author?: { 184 | iconUrl?: string, 185 | name?: string, 186 | url?: string, 187 | }, 188 | color?: number, 189 | description?: string, 190 | fields?: Array<{ 191 | inline?: boolean, 192 | name: string, 193 | value: string, 194 | }>, 195 | footer?: { 196 | iconUrl?: string, 197 | text: string, 198 | }, 199 | image?: { 200 | url?: string, 201 | }, 202 | provider?: { 203 | name?: string, 204 | url?: string, 205 | }, 206 | thumbnail?: { 207 | url?: string, 208 | }, 209 | timestamp?: string, 210 | title?: string, 211 | type?: string, 212 | url?: string, 213 | video?: { 214 | url?: string, 215 | }, 216 | } 217 | 218 | export interface CreateChannelMessageThread { 219 | autoArchiveDuration: number, 220 | name: string, 221 | reason?: string, 222 | } 223 | 224 | export interface CreateChannelOverwrite { 225 | allow: number, 226 | deny: number, 227 | id: string, 228 | type: number | string, 229 | } 230 | 231 | export interface CreateChannelThread { 232 | autoArchiveDuration: number, 233 | name: string, 234 | reason?: string, 235 | type?: number, 236 | } 237 | 238 | export interface CreateDm { 239 | recipientId?: string, 240 | recipients?: Array, 241 | } 242 | 243 | export interface CreateGuild { 244 | afkChannelId?: string, 245 | afkTimeout?: number, 246 | channels?: Array, 247 | defaultMessageNotifications?: number, 248 | explicitContentFilter?: number, 249 | icon?: Buffer | string, 250 | name: string, 251 | region: string, 252 | roles?: Array, 253 | systemChannelFlags?: number, 254 | systemChannelId?: string, 255 | verificationLevel?: number, 256 | } 257 | 258 | export interface CreateGuildBan { 259 | deleteMessageDays?: string, 260 | reason?: string, 261 | } 262 | 263 | export interface CreateGuildChannel { 264 | branchId?: string, 265 | bitrate?: number, 266 | name: string, 267 | nsfw?: boolean, 268 | parentId?: string, 269 | permissionOverwrites?: Array, 270 | reason?: string, 271 | skuId?: string, 272 | topic?: string, 273 | type: number, 274 | userLimit?: number, 275 | } 276 | 277 | export interface CreateGuildEmoji { 278 | name: string, 279 | image: Buffer | string, 280 | reason?: string, 281 | roles?: Array, 282 | } 283 | 284 | export interface CreateGuildIntegration { 285 | id: string, 286 | reason?: string, 287 | type: string, 288 | } 289 | 290 | export interface CreateGuildRole { 291 | color?: number, 292 | hoist?: boolean, 293 | mentionable?: boolean, 294 | name?: string, 295 | permissions?: number, 296 | reason?: string, 297 | } 298 | 299 | export interface CreateGuildSticker { 300 | description: string, 301 | file: File, 302 | name: string, 303 | reason?: string, 304 | tags: string, 305 | } 306 | 307 | export interface CreateGuildTemplate { 308 | description?: string, 309 | name: string, 310 | } 311 | 312 | export interface CreateInteractionResponse { 313 | data?: CreateInteractionResponseInnerPayload, 314 | type: number, 315 | } 316 | 317 | export interface CreateInteractionResponseInnerPayload { 318 | allowedMentions?: { 319 | parse?: Array, 320 | roles?: Array, 321 | users?: Array, 322 | }, 323 | components?: Array> | toJSON>, 324 | content?: string, 325 | embed?: CreateChannelMessageEmbed | toJSON | null, 326 | embeds?: Array>, 327 | file?: File, 328 | files?: Array, 329 | flags?: number, 330 | hasSpoiler?: boolean, 331 | tts?: boolean, 332 | } 333 | 334 | export interface CreateInteractionResponseData { 335 | data?: { 336 | allowed_mentions?: { 337 | parse?: Array, 338 | roles?: Array, 339 | users?: Array, 340 | }, 341 | components?: Array> | toJSON>, 342 | content?: string, 343 | embeds?: Array>, 344 | flags?: number, 345 | tts?: boolean, 346 | }, 347 | type: number, 348 | } 349 | 350 | export interface CreateLobby { 351 | capacity?: number, 352 | locked?: boolean, 353 | metadata?: any, 354 | ownerId?: string, 355 | type?: number, 356 | } 357 | 358 | export interface CreateMeBillingPaymentSource { 359 | billingAddress: { 360 | city: string, 361 | country: string, 362 | line1: string, 363 | line2: string, 364 | name: string, 365 | postalCode: string, 366 | state: string, 367 | }, 368 | paymentGateway: string, 369 | token: string, 370 | } 371 | 372 | export interface CreateMeBillingSubscription { 373 | paymentGatewayPlanId: string, 374 | paymentSourceId: string, 375 | trialId?: string, 376 | } 377 | 378 | export interface CreateMessage { 379 | activity?: { 380 | partyId?: string, 381 | sessionId?: string, 382 | type?: number, 383 | }, 384 | allowedMentions?: { 385 | parse?: Array, 386 | repliedUser?: boolean, 387 | roles?: Array, 388 | users?: Array, 389 | }, 390 | applicationId?: string, 391 | components?: Array> | toJSON>, 392 | content?: string, 393 | embed?: CreateChannelMessageEmbed | toJSON | null, 394 | embeds?: Array>, 395 | file?: File, 396 | files?: Array, 397 | hasSpoiler?: boolean, 398 | messageReference?: { 399 | channelId?: string, 400 | failIfNotExists?: boolean, 401 | guildId?: string, 402 | messageId: string, 403 | }, 404 | nonce?: string, 405 | stickerIds?: Array, 406 | tts?: boolean, 407 | } 408 | 409 | export interface CreateMessageData { 410 | activity?: { 411 | party_id?: string, 412 | session_id?: string, 413 | type?: number, 414 | }, 415 | allowed_mentions?: { 416 | parse?: Array, 417 | replied_user?: boolean, 418 | roles?: Array, 419 | users?: Array, 420 | }, 421 | application_id?: string, 422 | components?: Array> | toJSON>, 423 | content?: string, 424 | embeds?: Array>, 425 | message_reference?: { 426 | channel_id: string, 427 | fail_if_not_exists?: boolean, 428 | guild_id?: string, 429 | message_id: string, 430 | }, 431 | nonce?: string, 432 | sticker_ids?: Array, 433 | tts?: boolean, 434 | } 435 | 436 | export interface CreateOauth2Application { 437 | name: string, 438 | teamId?: string, 439 | } 440 | 441 | export interface CreateOauth2ApplicationAsset { 442 | image: Buffer | string, 443 | name: string, 444 | type: string, 445 | } 446 | 447 | export interface CreateOauth2Token { 448 | clientId?: string, 449 | clientSecret?: string, 450 | code?: string, 451 | grantType: string, 452 | redirectUri?: string, 453 | scope?: Array | string, 454 | } 455 | 456 | export interface CreateStageInstance { 457 | channelId: string, 458 | topic: string, 459 | } 460 | 461 | export interface CreateStoreApplicationAsset { 462 | file?: File, 463 | files?: Array, 464 | } 465 | 466 | export interface CreateTeam { 467 | icon?: Buffer | string | null, 468 | name?: string, 469 | } 470 | 471 | export interface CreateWebhook { 472 | avatar?: string, 473 | name: string, 474 | } 475 | 476 | export interface DeleteAccount { 477 | code?: string, 478 | password: string, 479 | } 480 | 481 | export interface DeleteChannel { 482 | reason?: string, 483 | } 484 | 485 | export interface DeleteChannelOverwrite { 486 | reason?: string, 487 | } 488 | 489 | export interface DeleteGuild { 490 | code?: string, 491 | } 492 | 493 | export interface DeleteGuildEmoji { 494 | reason?: string, 495 | } 496 | 497 | export interface DeleteGuildIntegration { 498 | reason?: string, 499 | } 500 | 501 | export interface DeleteGuildRole { 502 | reason?: string, 503 | } 504 | 505 | export interface DeleteGuildSticker { 506 | reason?: string, 507 | } 508 | 509 | export interface DeleteInvite { 510 | reason?: string, 511 | } 512 | 513 | export interface DeleteMessage { 514 | reason?: string, 515 | } 516 | 517 | export interface DeleteOauth2Application { 518 | code?: string, 519 | } 520 | 521 | export interface DeleteTeam { 522 | code?: string, 523 | } 524 | 525 | export interface DeleteWebhook { 526 | reason?: string, 527 | } 528 | 529 | export interface DisableAccount { 530 | code?: string, 531 | password: string, 532 | } 533 | 534 | export type EditApplicationCommand = Partial; 535 | export type EditApplicationCommandData = Partial; 536 | 537 | export type EditApplicationGuildCommand = Partial; 538 | export type EditApplicationGuildCommandData = Partial; 539 | 540 | export interface EditApplicationGuildCommandPermission { 541 | id: string, 542 | permission: boolean, 543 | type: string, 544 | } 545 | 546 | export interface EditApplicationGuildCommandPermissions { 547 | permissions: Array, 548 | } 549 | 550 | export interface EditApplicationNews { 551 | channelId?: string, 552 | description?: string, 553 | messageId?: string, 554 | thumbnail?: Buffer | string, 555 | title?: string, 556 | } 557 | 558 | export interface EditChannel { 559 | archived?: boolean, 560 | autoArchiveDuration?: number, 561 | bitrate?: number, 562 | icon?: Buffer | string, 563 | locked?: boolean, 564 | name?: string, 565 | nsfw?: boolean, 566 | parentId?: string, 567 | permissionOverwrites?: Array, 568 | position?: string, 569 | rateLimitPerUser?: number, 570 | reason?: string, 571 | rtcRegion?: string, 572 | topic?: string, 573 | type?: number, 574 | userLimit?: number, 575 | videoQualityMode?: number, 576 | } 577 | 578 | export interface EditChannelOverwrite { 579 | allow?: number, 580 | deny?: number, 581 | reason?: string, 582 | type?: number | string, 583 | } 584 | 585 | export interface EditConnection { 586 | friendSync?: boolean, 587 | visibility?: boolean, 588 | } 589 | 590 | export interface EditGuild { 591 | afkChannelId?: null | string, 592 | afkTimeout?: number, 593 | banner?: Buffer | string, 594 | code?: string, 595 | defaultMessageNotifications?: string, 596 | description?: string, 597 | discoverySplash?: Buffer | string | null, 598 | explicitContentFilter?: number, 599 | features?: Array, 600 | icon?: Buffer | string | null, 601 | name?: string, 602 | ownerId?: string, 603 | preferredLocale?: string, 604 | publicUpdatesChannelId?: string, 605 | reason?: string, 606 | region?: string, 607 | rulesChannelId?: null | string, 608 | splash?: Buffer | string | null, 609 | systemChannelFlags?: number, 610 | systemChannelId?: null | string, 611 | verificationLevel?: number, 612 | } 613 | 614 | export interface EditGuildChannel { 615 | id: string, 616 | lockPermissions?: boolean, 617 | parentId?: string, 618 | position?: number, 619 | } 620 | 621 | export interface EditGuildChannels extends Array { 622 | 623 | } 624 | 625 | export interface EditGuildChannelsExtra { 626 | reason?: string, 627 | } 628 | 629 | export interface EditGuildEmbed { 630 | channelId?: string, 631 | enabled: boolean, 632 | reason?: string, 633 | } 634 | 635 | export interface EditGuildEmoji { 636 | name?: string, 637 | reason?: string, 638 | roles?: Array, 639 | } 640 | 641 | export interface EditGuildIntegration { 642 | enableEmoticons?: boolean, 643 | expireBehavior?: number, 644 | expireGracePeriod?: number, 645 | reason?: string, 646 | } 647 | 648 | export interface EditGuildMember { 649 | channelId?: string | null, 650 | deaf?: boolean, 651 | mute?: boolean, 652 | nick?: string, 653 | reason?: string, 654 | roles?: Array, 655 | } 656 | 657 | export interface EditGuildMemberVerification { 658 | description?: string, 659 | enabled?: boolean, 660 | formFields?: Array, 661 | } 662 | 663 | export interface EditGuildMfaLevel { 664 | code: string, 665 | level: number, 666 | reason?: string, 667 | } 668 | 669 | export interface EditGuildNick { 670 | reason?: string, 671 | } 672 | 673 | export interface EditGuildRole { 674 | color?: number, 675 | hoist?: boolean, 676 | icon?: Buffer | string, 677 | mentionable?: boolean, 678 | name?: string, 679 | permissions?: number, 680 | reason?: string, 681 | } 682 | 683 | export interface EditGuildRolePosition { 684 | id: string, 685 | position?: number, 686 | } 687 | 688 | export interface EditGuildRolePositions extends Array { 689 | 690 | } 691 | 692 | export interface EditGuildRolePositionsExtra { 693 | reason?: string, 694 | } 695 | 696 | export interface EditGuildSticker { 697 | description?: string, 698 | name?: string, 699 | reason?: string, 700 | tags?: string, 701 | } 702 | 703 | export interface EditGuildVanity { 704 | reason?: string, 705 | } 706 | 707 | export interface EditGuildVoiceState { 708 | channelId: string, 709 | requestToSpeakTimestamp?: null | Date | string, 710 | suppress?: boolean, 711 | } 712 | 713 | export interface EditLobby { 714 | capacity?: number, 715 | locked?: boolean, 716 | metadata?: any, 717 | ownerId?: string, 718 | type?: number, 719 | } 720 | 721 | export interface EditLobbyMember { 722 | metadata?: any, 723 | } 724 | 725 | export interface EditMe { 726 | avatar?: Buffer | null | string, 727 | code?: string, 728 | customStatus?: { 729 | emojiId?: string, 730 | emojiName?: string, 731 | expiresAt?: Date | string, 732 | text?: string, 733 | }, 734 | discriminator?: number | string, 735 | email?: string, 736 | flags?: number, 737 | newPassword?: string, 738 | password?: string, 739 | username?: string, 740 | } 741 | 742 | export interface EditMeBillingPaymentSource { 743 | billingAddress?: { 744 | city: string, 745 | country: string, 746 | line1: string, 747 | line2: string, 748 | name: string, 749 | postalCode: string, 750 | state: string, 751 | }, 752 | default?: boolean, 753 | } 754 | 755 | export interface EditMeBillingSubscription { 756 | paymentGatewayPlanId?: string, 757 | paymentSourceId?: string, 758 | status?: string, 759 | } 760 | 761 | export interface EditMessage { 762 | allowedMentions?: { 763 | parse?: Array, 764 | repliedUser?: boolean, 765 | roles?: Array, 766 | users?: Array, 767 | }, 768 | attachments?: Array<{id: string}>, 769 | components?: Array> | toJSON>, 770 | content?: string, 771 | embed?: CreateChannelMessageEmbed | toJSON | null, 772 | embeds?: Array>, 773 | file?: File, 774 | files?: Array, 775 | flags?: number, 776 | hasSpoiler?: boolean, 777 | } 778 | 779 | export interface EditMessageData { 780 | allowed_mentions?: { 781 | parse?: Array, 782 | replied_user?: boolean, 783 | roles?: Array, 784 | users?: Array, 785 | }, 786 | attachments?: Array<{id: string}>, 787 | components?: Array> | toJSON>, 788 | content?: string, 789 | embeds?: Array>, 790 | flags?: number, 791 | } 792 | 793 | export interface EditOauth2Application { 794 | description?: string, 795 | icon?: Buffer | string, 796 | name?: string, 797 | redirectUris?: Array, 798 | } 799 | 800 | export interface EditSettings { 801 | [key: string]: any, 802 | } 803 | 804 | export interface EditStageInstance { 805 | topic?: string, 806 | } 807 | 808 | export interface EditTeam { 809 | code?: string, 810 | icon?: Buffer | string | null, 811 | name?: string, 812 | ownerUserId?: string, 813 | } 814 | 815 | export interface EditWebhook { 816 | avatar?: Buffer | string | null, 817 | channelId?: string, 818 | name?: string, 819 | reason?: string, 820 | } 821 | 822 | export interface EditWebhookTokenMessage { 823 | allowedMentions?: { 824 | parse?: Array, 825 | roles?: Array, 826 | users?: Array, 827 | }, 828 | attachments?: Array<{id: string}>, 829 | components?: Array> | toJSON>, 830 | content?: string, 831 | embed?: CreateChannelMessageEmbed | toJSON | null, 832 | embeds?: Array>, 833 | file?: File, 834 | files?: Array, 835 | hasSpoiler?: boolean, 836 | } 837 | 838 | export interface EditWebhookTokenMessageData { 839 | allowed_mentions?: { 840 | parse?: Array, 841 | roles?: Array, 842 | users?: Array, 843 | }, 844 | attachments?: Array<{id: string}>, 845 | components?: Array> | toJSON>, 846 | content?: string, 847 | embeds?: Array>, 848 | } 849 | 850 | export interface ExecuteWebhook { 851 | allowedMentions?: { 852 | parse?: Array, 853 | roles?: Array, 854 | users?: Array, 855 | }, 856 | avatarUrl?: string, 857 | components?: Array> | toJSON>, 858 | content?: string, 859 | embed?: CreateChannelMessageEmbed | toJSON | null, 860 | embeds?: Array>, 861 | file?: File, 862 | files?: Array, 863 | flags?: number, 864 | hasSpoiler?: boolean, 865 | threadId?: string, 866 | tts?: boolean, 867 | username?: string, 868 | wait?: boolean, 869 | } 870 | 871 | export interface ExecuteWebhookData { 872 | allowed_mentions?: { 873 | parse?: Array, 874 | roles?: Array, 875 | users?: Array, 876 | }, 877 | avatar_url?: string, 878 | components?: Array> | toJSON>, 879 | content?: string, 880 | embeds?: Array>, 881 | flags?: number, 882 | tts?: boolean, 883 | username?: string, 884 | } 885 | 886 | export interface FetchChannelThreadsArchivedPrivate { 887 | before?: Date | string, 888 | limit?: number, 889 | } 890 | 891 | export interface FetchChannelThreadsArchivedPrivateJoined { 892 | before?: string, 893 | limit?: number, 894 | } 895 | 896 | export interface FetchChannelThreadsArchivedPublic { 897 | before?: Date | string, 898 | limit?: number, 899 | } 900 | 901 | export interface FetchGiftCode { 902 | countryCode?: string, 903 | withApplication?: boolean, 904 | withSubscriptionPlan?: boolean, 905 | } 906 | 907 | export interface FetchGuild { 908 | withCounts?: boolean, 909 | } 910 | 911 | export interface FetchGuildAuditLogs { 912 | actionType?: number, 913 | before?: string, 914 | limit?: number, 915 | userId?: string, 916 | } 917 | 918 | export interface FetchGuildMembers { 919 | after?: string, 920 | limit?: number, 921 | } 922 | 923 | export interface FetchGuildMembersSearch { 924 | limit?: number, 925 | query: string, 926 | } 927 | 928 | export interface FetchGuildPruneCount { 929 | days?: number, 930 | includeRoles?: Array, 931 | } 932 | 933 | export interface FetchGuildWidgetPng { 934 | style?: string, 935 | } 936 | 937 | export interface FetchInvite { 938 | withCounts?: boolean, 939 | withExpiration?: boolean, 940 | } 941 | 942 | export interface FetchMe { 943 | withAnalyticsToken?: boolean, 944 | } 945 | 946 | export interface FetchMeBillingPayments { 947 | beforeId?: string, 948 | limit?: number, 949 | } 950 | 951 | export interface FetchMeFeedSettings { 952 | includeAutosubscribedGames?: boolean, 953 | } 954 | 955 | export interface FetchMeGuilds { 956 | after?: string, 957 | before?: string, 958 | limit?: number, 959 | } 960 | 961 | export interface FetchMentions { 962 | after?: string, 963 | around?: string, 964 | before?: string, 965 | everyone?: boolean, 966 | limit?: number, 967 | roles?: boolean, 968 | } 969 | 970 | export interface FetchMessages { 971 | after?: string, 972 | around?: string, 973 | before?: string, 974 | limit?: number, 975 | } 976 | 977 | export interface FetchOauth2Applications { 978 | withTeamApplications?: boolean, 979 | } 980 | 981 | export interface FetchOauth2Authorize { 982 | clientId?: string, 983 | responseType?: string, 984 | scope?: string, 985 | } 986 | 987 | export interface FetchReactions { 988 | after?: string, 989 | before?: string, 990 | limit?: number, 991 | } 992 | 993 | export interface FetchTeamPayouts { 994 | limit?: number, 995 | } 996 | 997 | export interface FollowChannel { 998 | webhookChannelId: string, 999 | } 1000 | 1001 | export interface ForgotPassword { 1002 | email: string, 1003 | } 1004 | 1005 | export interface JoinGuild { 1006 | lurker?: boolean, 1007 | sessionId?: string, 1008 | } 1009 | 1010 | export interface Login { 1011 | captchaKey?: string, 1012 | email: string, 1013 | giftCodeSKUId?: string, 1014 | loginSource?: string, 1015 | password: string, 1016 | undelete?: boolean, 1017 | } 1018 | 1019 | export interface LoginMfaSms { 1020 | code: string, 1021 | giftCodeSKUId?: string, 1022 | loginSource?: string, 1023 | ticket: string, 1024 | } 1025 | 1026 | export interface LoginMfaSmsSend { 1027 | ticket: string, 1028 | } 1029 | 1030 | export interface LoginMfaTotp { 1031 | code: string, 1032 | giftCodeSKUId?: string, 1033 | loginSource?: string, 1034 | ticket: string, 1035 | } 1036 | 1037 | export interface Logout { 1038 | provider?: string, 1039 | token?: string, 1040 | voipProvider?: string, 1041 | voipToken?: string, 1042 | } 1043 | 1044 | export interface MessageSuppressEmbeds { 1045 | suppress?: boolean, 1046 | } 1047 | 1048 | export interface Oauth2Authorize { 1049 | authorize?: boolean, 1050 | botGuildId?: string, 1051 | captchaKey?: string, 1052 | clientId?: string, 1053 | permissions?: number, 1054 | prompt?: string, 1055 | redirectUri?: string, 1056 | responseType?: string, 1057 | scope?: string, 1058 | webhookChannelId?: string, 1059 | webhookGuildId?: string, 1060 | } 1061 | 1062 | export interface RedeemGiftCode { 1063 | channelId?: string, 1064 | } 1065 | 1066 | export interface Register { 1067 | captchaKey?: string, 1068 | consent: boolean, 1069 | email: string, 1070 | fingerprint?: string, 1071 | giftCodeSKUId?: string, 1072 | invite?: string, 1073 | password: string, 1074 | username: string, 1075 | } 1076 | 1077 | export interface RemoveGuildBan { 1078 | reason?: string, 1079 | } 1080 | 1081 | export interface RemoveGuildMember { 1082 | reason?: string, 1083 | } 1084 | 1085 | export interface RemoveGuildMemberRole { 1086 | reason?: string, 1087 | } 1088 | 1089 | export interface ResetPassword { 1090 | password: string, 1091 | pushProvider?: string, 1092 | pushToken?: string, 1093 | pushVoipProvider?: string, 1094 | pushVoipToken?: string, 1095 | token: string, 1096 | } 1097 | 1098 | export interface ResetPasswordMfa { 1099 | code: string, 1100 | password: string, 1101 | ticket: string, 1102 | token: string, 1103 | } 1104 | 1105 | export interface SearchLobbies { 1106 | filter?: Array<{key: string, comparison: number, cast: number, value: string}>, 1107 | sort?: Array<{key: string, cast: number, near_value: string}>, 1108 | limit?: number, 1109 | distance?: number, 1110 | } 1111 | 1112 | export interface SearchOptions { 1113 | attachmentFilename?: string | Array, 1114 | attachmentExtensions?: string | Array, 1115 | authorId?: string | Array, 1116 | channelId?: string, 1117 | content?: string, 1118 | has?: string | Array, 1119 | includeNSFW?: boolean, 1120 | limit?: number, 1121 | maxId?: string, 1122 | mentions?: string | Array, 1123 | minId?: string, 1124 | offset?: number, 1125 | } 1126 | 1127 | export interface SendFriendRequest { 1128 | discriminator: string, 1129 | username: string, 1130 | } 1131 | 1132 | export interface StartChannelCallRinging { 1133 | recipients?: Array, 1134 | } 1135 | 1136 | export interface StopChannelCallRinging { 1137 | recipients?: Array, 1138 | } 1139 | 1140 | export interface TransferOauth2Application { 1141 | code?: string, 1142 | teamId: string, 1143 | } 1144 | 1145 | export interface Verify { 1146 | captchaKey: string, 1147 | token?: string, 1148 | } 1149 | 1150 | export interface VerifyCaptcha { 1151 | captchaKey: string, 1152 | } 1153 | 1154 | /* Raw Types */ 1155 | export interface RawChannelMessageComponent { 1156 | components?: Array>, 1157 | custom_id?: string, 1158 | disabled?: boolean, 1159 | emoji?: RawEmojiPartial, 1160 | label?: string, 1161 | max_values?: number, 1162 | min_values?: number, 1163 | options?: Array, 1164 | placeholder?: string, 1165 | style?: number, 1166 | type: number, 1167 | url?: string, 1168 | } 1169 | 1170 | export interface RawChannelMessageComponentSelectMenuOption { 1171 | default?: boolean, 1172 | description?: string, 1173 | emoji?: RawEmojiPartial, 1174 | label: string, 1175 | value: string, 1176 | } 1177 | 1178 | export interface RawChannelMessageEmbed { 1179 | author?: { 1180 | icon_url?: string, 1181 | name?: string, 1182 | url?: string, 1183 | }, 1184 | color?: number, 1185 | description?: string, 1186 | fields?: Array<{ 1187 | inline?: boolean, 1188 | name: string, 1189 | value: string, 1190 | }>, 1191 | footer?: { 1192 | icon_url?: string, 1193 | text: string, 1194 | }, 1195 | image?: { 1196 | url?: string, 1197 | }, 1198 | provider?: { 1199 | name?: string, 1200 | url?: string, 1201 | }, 1202 | thumbnail?: { 1203 | url?: string, 1204 | }, 1205 | timestamp?: string, 1206 | title?: string, 1207 | type?: string, 1208 | url?: string, 1209 | video?: { 1210 | url?: string, 1211 | }, 1212 | } 1213 | 1214 | export interface RawEmojiPartial { 1215 | animated?: boolean, 1216 | id?: string, 1217 | name?: string, 1218 | } 1219 | 1220 | /* Route Types */ 1221 | 1222 | export interface RouteInvite { 1223 | username?: string, 1224 | } 1225 | 1226 | export interface RouteWidget { 1227 | id?: string, 1228 | theme?: string, 1229 | username?: string, 1230 | } 1231 | } 1232 | 1233 | export namespace ResponseTypes { 1234 | export type CreateMessage = DiscordTypes.Message; 1235 | export type EditMessage = DiscordTypes.Message; 1236 | } 1237 | 1238 | 1239 | export namespace DiscordTypes { 1240 | export interface ChannelPartial { 1241 | id: string, 1242 | name: string, 1243 | } 1244 | 1245 | export interface Message { 1246 | activity?: { 1247 | cover_image?: string, 1248 | name?: string, 1249 | party_id: string, 1250 | type: number, 1251 | }, 1252 | application?: { 1253 | cover_image: null | string, 1254 | description: string, 1255 | icon: null | string, 1256 | id: string, 1257 | name: string, 1258 | primary_sku_id: string, 1259 | }, 1260 | attachments?: Array, 1261 | author: User, 1262 | call?: { 1263 | ended_timestamp: null | string, 1264 | participiants: Array, 1265 | }, 1266 | channel_id: string, 1267 | content: string, 1268 | edited_timestamp?: string, 1269 | embeds?: Array, 1270 | guild_id?: string, 1271 | id: string, 1272 | mention_channels?: Array, 1273 | mention_everyone: boolean, 1274 | mention_roles: Array, 1275 | mentions: Array<{ 1276 | bot: boolean, 1277 | discriminator: string, 1278 | id: string, 1279 | username: string, 1280 | }>, 1281 | message_reference?: { 1282 | channel_id: string, 1283 | guild_id?: string, 1284 | message_id: string, 1285 | }, 1286 | nonce: null | string, 1287 | pinned: boolean, 1288 | timestamp: string, 1289 | tts: boolean, 1290 | type: number, 1291 | webhook_id?: string, 1292 | } 1293 | 1294 | export interface MessageAttachment { 1295 | filename: string, 1296 | height: number, 1297 | id: string, 1298 | proxy_url: string, 1299 | size: number, 1300 | url: string, 1301 | width: number, 1302 | } 1303 | 1304 | export interface MessageEmbed { 1305 | author?: { 1306 | icon_url?: string, 1307 | name?: string, 1308 | proxy_icon_url?: string, 1309 | url?: string, 1310 | }, 1311 | color?: number, 1312 | description?: string, 1313 | fields?: Array<{ 1314 | inline?: boolean, 1315 | name: string, 1316 | value: string, 1317 | }>, 1318 | footer?: { 1319 | icon_url?: string, 1320 | proxy_icon_url?: string, 1321 | text: string, 1322 | }, 1323 | image?: { 1324 | height?: number, 1325 | proxy_url?: string, 1326 | url?: string, 1327 | width?: number, 1328 | }, 1329 | provider?: { 1330 | name?: string, 1331 | url?: string, 1332 | }, 1333 | reference_id?: string, 1334 | thumbnail?: { 1335 | height?: number, 1336 | proxy_url?: string, 1337 | url?: string, 1338 | width?: number, 1339 | }, 1340 | timestamp?: string, 1341 | title?: string, 1342 | type?: string, 1343 | url?: string, 1344 | video?: { 1345 | height?: number, 1346 | url?: string, 1347 | width?: number, 1348 | }, 1349 | } 1350 | 1351 | export interface User { 1352 | avatar: null | string, 1353 | bot: boolean, 1354 | discriminator: string, 1355 | id: string, 1356 | username: string, 1357 | } 1358 | } 1359 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import { SPOILER_ATTACHMENT_PREFIX } from './constants'; 2 | import { RequestTypes } from './types'; 3 | 4 | 5 | export function spoilerfy(file: RequestTypes.File): RequestTypes.File { 6 | if (file.filename && !file.filename.startsWith(SPOILER_ATTACHMENT_PREFIX)) { 7 | file.filename = `${SPOILER_ATTACHMENT_PREFIX}${file.filename}`; 8 | } 9 | return file; 10 | } 11 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "outDir": "./lib", 7 | "strict": true, 8 | "target": "esnext" 9 | }, 10 | "include": ["src"], 11 | "exclude": ["node_modules"], 12 | "typedocOptions": { 13 | "name": "Detritus Rest Client", 14 | "out": "./docs", 15 | "entryPoints": [ 16 | "./src" 17 | ] 18 | } 19 | } 20 | --------------------------------------------------------------------------------