@discordeno/rest 19.0.0-next.0b02607 → 19.0.0-next.0b93eed
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/invalidBucket.d.ts +6 -7
- package/dist/invalidBucket.d.ts.map +1 -1
- package/dist/invalidBucket.js +23 -25
- package/dist/invalidBucket.js.map +1 -1
- package/dist/manager.d.ts +9 -0
- package/dist/manager.d.ts.map +1 -1
- package/dist/manager.js +290 -84
- package/dist/manager.js.map +1 -1
- package/dist/queue.d.ts +5 -0
- package/dist/queue.d.ts.map +1 -1
- package/dist/queue.js +15 -11
- package/dist/queue.js.map +1 -1
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +42 -4
- package/dist/routes.js.map +1 -1
- package/dist/types.d.ts +217 -16
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/typings/routes.d.ts +24 -4
- package/dist/typings/routes.d.ts.map +1 -1
- package/dist/typings/routes.js.map +1 -1
- package/package.json +5 -5
package/dist/manager.js
CHANGED
|
@@ -1,34 +1,50 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/restrict-template-expressions */ /* eslint-disable no-const-assign */ import {
|
|
1
|
+
/* eslint-disable @typescript-eslint/restrict-template-expressions */ /* eslint-disable no-const-assign */ import { Buffer } from 'node:buffer';
|
|
2
2
|
import { calculateBits, camelize, camelToSnakeCase, delay, getBotIdFromToken, logger, processReactionString, urlToBase64 } from '@discordeno/utils';
|
|
3
|
-
import fetch from 'node-fetch';
|
|
4
3
|
import { createInvalidRequestBucket } from './invalidBucket.js';
|
|
5
4
|
import { Queue } from './queue.js';
|
|
5
|
+
import { InteractionResponseTypes } from '@discordeno/types';
|
|
6
6
|
import { createRoutes } from './routes.js';
|
|
7
7
|
// TODO: make dynamic based on package.json file
|
|
8
8
|
const version = '19.0.0-alpha.1';
|
|
9
|
+
export const DISCORD_API_VERSION = 10;
|
|
10
|
+
export const DISCORD_API_URL = 'https://discord.com/api';
|
|
11
|
+
export const AUDIT_LOG_REASON_HEADER = 'x-audit-log-reason';
|
|
12
|
+
export const RATE_LIMIT_REMAINING_HEADER = 'x-ratelimit-remaining';
|
|
13
|
+
export const RATE_LIMIT_RESET_AFTER_HEADER = 'x-ratelimit-reset-after';
|
|
14
|
+
export const RATE_LIMIT_GLOBAL_HEADER = 'x-ratelimit-global';
|
|
15
|
+
export const RATE_LIMIT_BUCKET_HEADER = 'x-ratelimit-bucket';
|
|
16
|
+
export const RATE_LIMIT_LIMIT_HEADER = 'x-ratelimit-limit';
|
|
17
|
+
export const RATE_LIMIT_SCOPE_HEADER = 'x-ratelimit-scope';
|
|
9
18
|
export function createRestManager(options) {
|
|
10
19
|
const applicationId = options.applicationId ? BigInt(options.applicationId) : options.token ? getBotIdFromToken(options.token) : undefined;
|
|
11
20
|
if (!applicationId) {
|
|
12
21
|
throw new Error('`applicationId` was not provided and was not able to extract the id from the bots token. Please explicitly pass `applicationId` to the rest manager.');
|
|
13
22
|
}
|
|
14
|
-
const baseUrl = options.proxy?.baseUrl ??
|
|
23
|
+
const baseUrl = options.proxy?.baseUrl ?? DISCORD_API_URL;
|
|
15
24
|
const rest = {
|
|
16
|
-
token: options.token,
|
|
17
25
|
applicationId,
|
|
18
|
-
|
|
26
|
+
authorization: options.proxy?.authorization,
|
|
27
|
+
authorizationHeader: options.proxy?.authorizationHeader ?? 'authorization',
|
|
19
28
|
baseUrl,
|
|
20
|
-
|
|
21
|
-
maxRetryCount: Infinity,
|
|
29
|
+
deleteQueueDelay: 60000,
|
|
22
30
|
globallyRateLimited: false,
|
|
31
|
+
invalidBucket: createInvalidRequestBucket({}),
|
|
32
|
+
isProxied: !baseUrl.startsWith(DISCORD_API_URL),
|
|
33
|
+
maxRetryCount: Infinity,
|
|
23
34
|
processingRateLimitedPaths: false,
|
|
24
|
-
deleteQueueDelay: 60000,
|
|
25
35
|
queues: new Map(),
|
|
26
36
|
rateLimitedPaths: new Map(),
|
|
27
|
-
|
|
28
|
-
|
|
37
|
+
token: options.token,
|
|
38
|
+
version: options.version ?? DISCORD_API_VERSION,
|
|
29
39
|
routes: createRoutes(),
|
|
30
|
-
|
|
31
|
-
|
|
40
|
+
createBaseHeaders () {
|
|
41
|
+
return {
|
|
42
|
+
'user-agent': `DiscordBot (https://github.com/discordeno/discordeno, v${version})`
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
checkRateLimits (url, headers) {
|
|
46
|
+
const authHeader = headers?.authorization ?? '';
|
|
47
|
+
const ratelimited = rest.rateLimitedPaths.get(`${authHeader}${url}`);
|
|
32
48
|
const global = rest.rateLimitedPaths.get('global');
|
|
33
49
|
const now = Date.now();
|
|
34
50
|
if (ratelimited && now < ratelimited.resetTimestamp) {
|
|
@@ -47,20 +63,27 @@ export function createRestManager(options) {
|
|
|
47
63
|
}
|
|
48
64
|
const newObj = {};
|
|
49
65
|
for (const key of Object.keys(obj)){
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
66
|
+
const value = obj[key];
|
|
67
|
+
// Some falsy values should be allowed like null or 0
|
|
68
|
+
if (value !== undefined) {
|
|
69
|
+
switch(key){
|
|
70
|
+
case 'permissions':
|
|
71
|
+
case 'allow':
|
|
72
|
+
case 'deny':
|
|
73
|
+
newObj[key] = typeof value === 'string' ? value : calculateBits(value);
|
|
74
|
+
continue;
|
|
75
|
+
case 'defaultMemberPermissions':
|
|
76
|
+
newObj.default_member_permissions = typeof value === 'string' ? value : calculateBits(value);
|
|
77
|
+
continue;
|
|
78
|
+
case 'nameLocalizations':
|
|
79
|
+
newObj.name_localizations = value;
|
|
80
|
+
continue;
|
|
81
|
+
case 'descriptionLocalizations':
|
|
82
|
+
newObj.description_localizations = value;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
58
85
|
}
|
|
59
|
-
|
|
60
|
-
newObj.default_member_permissions = calculateBits(obj[key]);
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
newObj[camelToSnakeCase(key)] = rest.changeToDiscordFormat(obj[key]);
|
|
86
|
+
newObj[camelToSnakeCase(key)] = rest.changeToDiscordFormat(value);
|
|
64
87
|
}
|
|
65
88
|
return newObj;
|
|
66
89
|
}
|
|
@@ -68,13 +91,11 @@ export function createRestManager(options) {
|
|
|
68
91
|
return obj;
|
|
69
92
|
},
|
|
70
93
|
createRequestBody (method, options) {
|
|
71
|
-
const headers =
|
|
72
|
-
|
|
73
|
-
};
|
|
74
|
-
if (options?.unauthorized !== false) headers.authorization = `Bot ${rest.token}`;
|
|
94
|
+
const headers = this.createBaseHeaders();
|
|
95
|
+
if (options?.unauthorized !== true) headers.authorization = `Bot ${rest.token}`;
|
|
75
96
|
// IF A REASON IS PROVIDED ENCODE IT IN HEADERS
|
|
76
97
|
if (options?.reason !== undefined) {
|
|
77
|
-
headers[
|
|
98
|
+
headers[AUDIT_LOG_REASON_HEADER] = encodeURIComponent(options?.reason);
|
|
78
99
|
}
|
|
79
100
|
let body;
|
|
80
101
|
// TODO: check if we need to add specific check for GET method
|
|
@@ -85,12 +106,21 @@ export function createRestManager(options) {
|
|
|
85
106
|
for(let i = 0; i < options.files.length; ++i){
|
|
86
107
|
form.append(`file${i}`, options.files[i].blob, options.files[i].name);
|
|
87
108
|
}
|
|
88
|
-
|
|
109
|
+
// Have to use changeToDiscordFormat or else JSON.stringify may throw an error for the presence of BigInt(s) in the json
|
|
110
|
+
form.append('payload_json', JSON.stringify(rest.changeToDiscordFormat({
|
|
89
111
|
...options.body,
|
|
90
112
|
files: undefined
|
|
91
|
-
}));
|
|
113
|
+
})));
|
|
114
|
+
// No need to set the `content-type` header since `fetch` does that automatically for us when we use a `FormData` object.
|
|
92
115
|
body = form;
|
|
93
|
-
|
|
116
|
+
} else if (options?.body && options.headers && options.headers['content-type'] === 'application/x-www-form-urlencoded') {
|
|
117
|
+
// OAuth2 body handling
|
|
118
|
+
const formBody = [];
|
|
119
|
+
const discordBody = rest.changeToDiscordFormat(options.body);
|
|
120
|
+
for(const prop in discordBody){
|
|
121
|
+
formBody.push(`${encodeURIComponent(prop)}=${encodeURIComponent(discordBody[prop])}`);
|
|
122
|
+
}
|
|
123
|
+
body = formBody.join('&');
|
|
94
124
|
} else if (options?.body !== undefined) {
|
|
95
125
|
if (options.body instanceof FormData) {
|
|
96
126
|
body = options.body;
|
|
@@ -137,17 +167,17 @@ export function createRestManager(options) {
|
|
|
137
167
|
}, 1000);
|
|
138
168
|
}
|
|
139
169
|
},
|
|
140
|
-
/** Processes the rate limit headers and determines if it needs to be rate limited and returns the bucket id if available */ processHeaders (url, headers) {
|
|
170
|
+
/** Processes the rate limit headers and determines if it needs to be rate limited and returns the bucket id if available */ processHeaders (url, headers, requestAuthorization) {
|
|
141
171
|
let rateLimited = false;
|
|
142
172
|
// GET ALL NECESSARY HEADERS
|
|
143
|
-
const remaining = headers.get(
|
|
144
|
-
const retryAfter = headers.get(
|
|
173
|
+
const remaining = headers.get(RATE_LIMIT_REMAINING_HEADER);
|
|
174
|
+
const retryAfter = headers.get(RATE_LIMIT_RESET_AFTER_HEADER);
|
|
145
175
|
const reset = Date.now() + Number(retryAfter) * 1000;
|
|
146
|
-
const global = headers.get(
|
|
176
|
+
const global = headers.get(RATE_LIMIT_GLOBAL_HEADER);
|
|
147
177
|
// undefined override null needed for typings
|
|
148
|
-
const bucketId = headers.get(
|
|
149
|
-
const limit = headers.get(
|
|
150
|
-
rest.queues.get(url)?.handleCompletedRequest({
|
|
178
|
+
const bucketId = headers.get(RATE_LIMIT_BUCKET_HEADER) ?? undefined;
|
|
179
|
+
const limit = headers.get(RATE_LIMIT_LIMIT_HEADER);
|
|
180
|
+
rest.queues.get(`${requestAuthorization}${url}`)?.handleCompletedRequest({
|
|
151
181
|
remaining: remaining ? Number(remaining) : undefined,
|
|
152
182
|
interval: retryAfter ? Number(retryAfter) * 1000 : undefined,
|
|
153
183
|
max: limit ? Number(limit) : undefined
|
|
@@ -156,14 +186,14 @@ export function createRestManager(options) {
|
|
|
156
186
|
if (remaining === '0') {
|
|
157
187
|
rateLimited = true;
|
|
158
188
|
// SAVE THE URL AS LIMITED, IMPORTANT FOR NEW REQUESTS BY USER WITHOUT BUCKET
|
|
159
|
-
rest.rateLimitedPaths.set(url
|
|
189
|
+
rest.rateLimitedPaths.set(`${requestAuthorization}${url}`, {
|
|
160
190
|
url,
|
|
161
191
|
resetTimestamp: reset,
|
|
162
192
|
bucketId
|
|
163
193
|
});
|
|
164
194
|
// SAVE THE BUCKET AS LIMITED SINCE DIFFERENT URLS MAY SHARE A BUCKET
|
|
165
195
|
if (bucketId) {
|
|
166
|
-
rest.rateLimitedPaths.set(bucketId
|
|
196
|
+
rest.rateLimitedPaths.set(`${requestAuthorization}${bucketId}`, {
|
|
167
197
|
url,
|
|
168
198
|
resetTimestamp: reset,
|
|
169
199
|
bucketId
|
|
@@ -172,8 +202,8 @@ export function createRestManager(options) {
|
|
|
172
202
|
}
|
|
173
203
|
// IF THERE IS NO REMAINING GLOBAL LIMIT, MARK IT RATE LIMITED GLOBALLY
|
|
174
204
|
if (global) {
|
|
175
|
-
const retryAfter = headers.get('retry-after');
|
|
176
|
-
const globalReset = Date.now() +
|
|
205
|
+
const retryAfter = Number(headers.get('retry-after')) * 1000;
|
|
206
|
+
const globalReset = Date.now() + retryAfter;
|
|
177
207
|
// rest.debug(
|
|
178
208
|
// `[REST = Globally Rate Limited] URL: ${url} | Global Rest: ${globalReset}`
|
|
179
209
|
// )
|
|
@@ -181,14 +211,14 @@ export function createRestManager(options) {
|
|
|
181
211
|
rateLimited = true;
|
|
182
212
|
setTimeout(()=>{
|
|
183
213
|
rest.globallyRateLimited = false;
|
|
184
|
-
},
|
|
214
|
+
}, retryAfter);
|
|
185
215
|
rest.rateLimitedPaths.set('global', {
|
|
186
216
|
url: 'global',
|
|
187
217
|
resetTimestamp: globalReset,
|
|
188
218
|
bucketId
|
|
189
219
|
});
|
|
190
220
|
if (bucketId) {
|
|
191
|
-
rest.rateLimitedPaths.set(bucketId
|
|
221
|
+
rest.rateLimitedPaths.set(`${requestAuthorization}${bucketId}`, {
|
|
192
222
|
url: 'global',
|
|
193
223
|
resetTimestamp: globalReset,
|
|
194
224
|
bucketId
|
|
@@ -203,17 +233,33 @@ export function createRestManager(options) {
|
|
|
203
233
|
async sendRequest (options) {
|
|
204
234
|
const url = `${rest.baseUrl}/v${rest.version}${options.route}`;
|
|
205
235
|
const payload = rest.createRequestBody(options.method, options.requestBodyOptions);
|
|
236
|
+
const loggingHeaders = {
|
|
237
|
+
...payload.headers
|
|
238
|
+
};
|
|
239
|
+
const authenticationScheme = payload.headers.authorization?.split(' ')[0];
|
|
240
|
+
if (payload.headers.authorization) {
|
|
241
|
+
loggingHeaders.authorization = `${authenticationScheme} tokenhere`;
|
|
242
|
+
}
|
|
206
243
|
logger.debug(`sending request to ${url}`, 'with payload:', {
|
|
207
244
|
...payload,
|
|
208
|
-
headers:
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
245
|
+
headers: loggingHeaders
|
|
246
|
+
});
|
|
247
|
+
const response = await fetch(url, payload).catch(async (error)=>{
|
|
248
|
+
logger.error(error);
|
|
249
|
+
// Mark request and completed
|
|
250
|
+
rest.invalidBucket.handleCompletedRequest(999, false);
|
|
251
|
+
options.reject({
|
|
252
|
+
ok: false,
|
|
253
|
+
status: 999,
|
|
254
|
+
error: 'Possible network or request shape issue occurred. If this is rare, its a network glitch. If it occurs a lot something is wrong.'
|
|
255
|
+
});
|
|
256
|
+
throw error;
|
|
212
257
|
});
|
|
213
|
-
const response = await fetch(url, payload);
|
|
214
258
|
logger.debug(`request fetched from ${url} with status ${response.status} & ${response.statusText}`);
|
|
259
|
+
// Mark request and completed
|
|
260
|
+
rest.invalidBucket.handleCompletedRequest(response.status, response.headers.get(RATE_LIMIT_SCOPE_HEADER) === 'shared');
|
|
215
261
|
// Set the bucket id if it was available on the headers
|
|
216
|
-
const bucketId = rest.processHeaders(rest.simplifyUrl(options.route, options.method), response.headers);
|
|
262
|
+
const bucketId = rest.processHeaders(rest.simplifyUrl(options.route, options.method), response.headers, authenticationScheme === 'Bearer' ? payload.headers.authorization : '');
|
|
217
263
|
if (bucketId) options.bucketId = bucketId;
|
|
218
264
|
if (response.status < 200 || response.status >= 400) {
|
|
219
265
|
logger.debug(`Request to ${url} failed.`);
|
|
@@ -238,9 +284,7 @@ export function createRestManager(options) {
|
|
|
238
284
|
return;
|
|
239
285
|
}
|
|
240
286
|
options.retryCount += 1;
|
|
241
|
-
|
|
242
|
-
rest.invalidBucket.handleCompletedRequest(response.status, response.headers.get('X-RateLimit-Scope') === 'shared');
|
|
243
|
-
const resetAfter = response.headers.get('x-ratelimit-reset-after');
|
|
287
|
+
const resetAfter = response.headers.get(RATE_LIMIT_RESET_AFTER_HEADER);
|
|
244
288
|
if (resetAfter) await delay(Number(resetAfter) * 1000);
|
|
245
289
|
// process the response to prevent mem leak
|
|
246
290
|
await response.arrayBuffer();
|
|
@@ -275,36 +319,35 @@ export function createRestManager(options) {
|
|
|
275
319
|
return parts.join('/');
|
|
276
320
|
},
|
|
277
321
|
async processRequest (request) {
|
|
278
|
-
const route = request.route.substring(request.route.indexOf('api/'));
|
|
279
|
-
const parts = route.split('/');
|
|
280
|
-
// Remove the api/
|
|
281
|
-
parts.shift();
|
|
282
|
-
// Removes the /v#/
|
|
283
|
-
if (parts[0]?.startsWith('v')) parts.shift();
|
|
284
|
-
// Set the full url to discord api in case it was recieved in a proxy rest
|
|
285
|
-
request.route = `${rest.baseUrl}/v${rest.version}/${parts.join('/')}`;
|
|
286
322
|
const url = rest.simplifyUrl(request.route, request.method);
|
|
287
323
|
if (request.runThroughQueue === false) {
|
|
288
324
|
await rest.sendRequest(request);
|
|
289
325
|
return;
|
|
290
326
|
}
|
|
291
|
-
const
|
|
327
|
+
const authHeader = request.requestBodyOptions?.headers?.authorization ?? '';
|
|
328
|
+
const queue = rest.queues.get(`${authHeader}${url}`);
|
|
292
329
|
if (queue !== undefined) {
|
|
293
330
|
queue.makeRequest(request);
|
|
294
331
|
} else {
|
|
295
332
|
// CREATES A NEW QUEUE
|
|
296
333
|
const bucketQueue = new Queue(rest, {
|
|
297
334
|
url,
|
|
298
|
-
deleteQueueDelay: rest.deleteQueueDelay
|
|
335
|
+
deleteQueueDelay: rest.deleteQueueDelay,
|
|
336
|
+
authentication: authHeader
|
|
299
337
|
});
|
|
300
338
|
// Add request to queue
|
|
301
339
|
bucketQueue.makeRequest(request);
|
|
302
340
|
// Save queue
|
|
303
|
-
rest.queues.set(url
|
|
341
|
+
rest.queues.set(`${authHeader}${url}`, bucketQueue);
|
|
304
342
|
}
|
|
305
343
|
},
|
|
306
344
|
async makeRequest (method, route, options) {
|
|
307
345
|
if (rest.isProxied) {
|
|
346
|
+
if (rest.authorization !== undefined) {
|
|
347
|
+
options ??= {};
|
|
348
|
+
options.headers ??= {};
|
|
349
|
+
options.headers[rest.authorizationHeader] = rest.authorization;
|
|
350
|
+
}
|
|
308
351
|
const result = await fetch(`${rest.baseUrl}/v${rest.version}${route}`, rest.createRequestBody(method, options));
|
|
309
352
|
if (!result.ok) {
|
|
310
353
|
const err = await result.json().catch(()=>{});
|
|
@@ -371,6 +414,11 @@ export function createRestManager(options) {
|
|
|
371
414
|
async addThreadMember (channelId, userId) {
|
|
372
415
|
await rest.put(rest.routes.channels.threads.user(channelId, userId));
|
|
373
416
|
},
|
|
417
|
+
async addDmRecipient (channelId, userId, body) {
|
|
418
|
+
await rest.put(rest.routes.channels.dmRecipient(channelId, userId), {
|
|
419
|
+
body
|
|
420
|
+
});
|
|
421
|
+
},
|
|
374
422
|
async createAutomodRule (guildId, body, reason) {
|
|
375
423
|
return await rest.post(rest.routes.guilds.automod.rules(guildId), {
|
|
376
424
|
body,
|
|
@@ -389,20 +437,34 @@ export function createRestManager(options) {
|
|
|
389
437
|
reason
|
|
390
438
|
});
|
|
391
439
|
},
|
|
392
|
-
async createGlobalApplicationCommand (body) {
|
|
393
|
-
|
|
440
|
+
async createGlobalApplicationCommand (body, options) {
|
|
441
|
+
const restOptions = {
|
|
394
442
|
body
|
|
395
|
-
}
|
|
443
|
+
};
|
|
444
|
+
if (options?.bearerToken) {
|
|
445
|
+
restOptions.unauthorized = true;
|
|
446
|
+
restOptions.headers = {
|
|
447
|
+
authorization: `Bearer ${options.bearerToken}`
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
return await rest.post(rest.routes.interactions.commands.commands(rest.applicationId), restOptions);
|
|
396
451
|
},
|
|
397
452
|
async createGuild (body) {
|
|
398
453
|
return await rest.post(rest.routes.guilds.all(), {
|
|
399
454
|
body
|
|
400
455
|
});
|
|
401
456
|
},
|
|
402
|
-
async createGuildApplicationCommand (body, guildId) {
|
|
403
|
-
|
|
457
|
+
async createGuildApplicationCommand (body, guildId, options) {
|
|
458
|
+
const restOptions = {
|
|
404
459
|
body
|
|
405
|
-
}
|
|
460
|
+
};
|
|
461
|
+
if (options?.bearerToken) {
|
|
462
|
+
restOptions.unauthorized = true;
|
|
463
|
+
restOptions.headers = {
|
|
464
|
+
authorization: `Bearer ${options.bearerToken}`
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
return await rest.post(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), restOptions);
|
|
406
468
|
},
|
|
407
469
|
async createGuildFromTemplate (templateCode, body) {
|
|
408
470
|
if (body.icon) {
|
|
@@ -595,7 +657,7 @@ export function createRestManager(options) {
|
|
|
595
657
|
},
|
|
596
658
|
async editBotProfile (options) {
|
|
597
659
|
const avatar = options?.botAvatarURL ? await urlToBase64(options?.botAvatarURL) : options?.botAvatarURL;
|
|
598
|
-
return await rest.patch(rest.routes.
|
|
660
|
+
return await rest.patch(rest.routes.currentUser(), {
|
|
599
661
|
body: {
|
|
600
662
|
username: options.username?.trim(),
|
|
601
663
|
avatar
|
|
@@ -669,7 +731,8 @@ export function createRestManager(options) {
|
|
|
669
731
|
},
|
|
670
732
|
async editMessage (channelId, messageId, body) {
|
|
671
733
|
return await rest.patch(rest.routes.channels.message(channelId, messageId), {
|
|
672
|
-
body
|
|
734
|
+
body,
|
|
735
|
+
files: body.files
|
|
673
736
|
});
|
|
674
737
|
},
|
|
675
738
|
async editOriginalInteractionResponse (token, body) {
|
|
@@ -771,14 +834,62 @@ export function createRestManager(options) {
|
|
|
771
834
|
async getActiveThreads (guildId) {
|
|
772
835
|
return await rest.get(rest.routes.channels.threads.active(guildId));
|
|
773
836
|
},
|
|
774
|
-
async getApplicationCommandPermission (guildId, commandId) {
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
837
|
+
async getApplicationCommandPermission (guildId, commandId, options) {
|
|
838
|
+
const restOptions = {};
|
|
839
|
+
if (options?.accessToken) {
|
|
840
|
+
restOptions.unauthorized = true;
|
|
841
|
+
restOptions.headers = {
|
|
842
|
+
authorization: `Bearer ${options.accessToken}`
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
return await rest.get(rest.routes.interactions.commands.permission(options?.applicationId ?? rest.applicationId, guildId, commandId), restOptions);
|
|
846
|
+
},
|
|
847
|
+
async getApplicationCommandPermissions (guildId, options) {
|
|
848
|
+
const restOptions = {};
|
|
849
|
+
if (options?.accessToken) {
|
|
850
|
+
restOptions.unauthorized = true;
|
|
851
|
+
restOptions.headers = {
|
|
852
|
+
authorization: `Bearer ${options.accessToken}`
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
return await rest.get(rest.routes.interactions.commands.permissions(options?.applicationId ?? rest.applicationId, guildId), restOptions);
|
|
779
856
|
},
|
|
780
857
|
async getApplicationInfo () {
|
|
781
|
-
return await rest.get(rest.routes.
|
|
858
|
+
return await rest.get(rest.routes.oauth2.application());
|
|
859
|
+
},
|
|
860
|
+
async getCurrentAuthenticationInfo (token) {
|
|
861
|
+
return await rest.get(rest.routes.oauth2.currentAuthorization(), {
|
|
862
|
+
headers: {
|
|
863
|
+
authorization: `Bearer ${token}`
|
|
864
|
+
},
|
|
865
|
+
unauthorized: true
|
|
866
|
+
});
|
|
867
|
+
},
|
|
868
|
+
async exchangeToken (clientId, clientSecret, body) {
|
|
869
|
+
const basicCredentials = Buffer.from(`${clientId}:${clientSecret}`);
|
|
870
|
+
const restOptions = {
|
|
871
|
+
body,
|
|
872
|
+
headers: {
|
|
873
|
+
'content-type': 'application/x-www-form-urlencoded',
|
|
874
|
+
authorization: `Basic ${basicCredentials.toString('base64')}`
|
|
875
|
+
},
|
|
876
|
+
unauthorized: true
|
|
877
|
+
};
|
|
878
|
+
if (body.grantType === 'client_credentials') {
|
|
879
|
+
restOptions.body.scope = body.scope.join(' ');
|
|
880
|
+
}
|
|
881
|
+
return await rest.post(rest.routes.oauth2.tokenExchange(), restOptions);
|
|
882
|
+
},
|
|
883
|
+
async revokeToken (clientId, clientSecret, body) {
|
|
884
|
+
const basicCredentials = Buffer.from(`${clientId}:${clientSecret}`);
|
|
885
|
+
await rest.post(rest.routes.oauth2.tokenRevoke(), {
|
|
886
|
+
body,
|
|
887
|
+
headers: {
|
|
888
|
+
'content-type': 'application/x-www-form-urlencoded',
|
|
889
|
+
authorization: `Basic ${basicCredentials.toString('base64')}`
|
|
890
|
+
},
|
|
891
|
+
unauthorized: true
|
|
892
|
+
});
|
|
782
893
|
},
|
|
783
894
|
async getAuditLog (guildId, options) {
|
|
784
895
|
return await rest.get(rest.routes.guilds.auditlogs(guildId, options));
|
|
@@ -817,6 +928,11 @@ export function createRestManager(options) {
|
|
|
817
928
|
}
|
|
818
929
|
});
|
|
819
930
|
},
|
|
931
|
+
async getGroupDmChannel (body) {
|
|
932
|
+
return await rest.post(rest.routes.channels.dm(), {
|
|
933
|
+
body
|
|
934
|
+
});
|
|
935
|
+
},
|
|
820
936
|
async getEmoji (guildId, emojiId) {
|
|
821
937
|
return await rest.get(rest.routes.guilds.emoji(guildId, emojiId));
|
|
822
938
|
},
|
|
@@ -842,6 +958,14 @@ export function createRestManager(options) {
|
|
|
842
958
|
}) {
|
|
843
959
|
return await rest.get(rest.routes.guilds.guild(guildId, options.counts));
|
|
844
960
|
},
|
|
961
|
+
async getGuilds (token, options) {
|
|
962
|
+
return await rest.get(rest.routes.guilds.userGuilds(options), {
|
|
963
|
+
headers: {
|
|
964
|
+
authorization: `Bearer ${token}`
|
|
965
|
+
},
|
|
966
|
+
unauthorized: true
|
|
967
|
+
});
|
|
968
|
+
},
|
|
845
969
|
async getGuildApplicationCommand (commandId, guildId) {
|
|
846
970
|
return await rest.get(rest.routes.interactions.commands.guilds.one(rest.applicationId, guildId, commandId));
|
|
847
971
|
},
|
|
@@ -937,6 +1061,30 @@ export function createRestManager(options) {
|
|
|
937
1061
|
async getUser (id) {
|
|
938
1062
|
return await rest.get(rest.routes.user(id));
|
|
939
1063
|
},
|
|
1064
|
+
async getCurrentUser (token) {
|
|
1065
|
+
return await rest.get(rest.routes.currentUser(), {
|
|
1066
|
+
headers: {
|
|
1067
|
+
authorization: `Bearer ${token}`
|
|
1068
|
+
},
|
|
1069
|
+
unauthorized: true
|
|
1070
|
+
});
|
|
1071
|
+
},
|
|
1072
|
+
async getUserConnections (token) {
|
|
1073
|
+
return await rest.get(rest.routes.oauth2.connections(), {
|
|
1074
|
+
headers: {
|
|
1075
|
+
authorization: `Bearer ${token}`
|
|
1076
|
+
},
|
|
1077
|
+
unauthorized: true
|
|
1078
|
+
});
|
|
1079
|
+
},
|
|
1080
|
+
async getUserApplicationRoleConnection (token, applicationId) {
|
|
1081
|
+
return await rest.get(rest.routes.oauth2.roleConnections(applicationId), {
|
|
1082
|
+
headers: {
|
|
1083
|
+
authorization: `Bearer ${token}`
|
|
1084
|
+
},
|
|
1085
|
+
unauthorized: true
|
|
1086
|
+
});
|
|
1087
|
+
},
|
|
940
1088
|
async getVanityUrl (guildId) {
|
|
941
1089
|
return await rest.get(rest.routes.guilds.vanity(guildId));
|
|
942
1090
|
},
|
|
@@ -981,6 +1129,9 @@ export function createRestManager(options) {
|
|
|
981
1129
|
async removeThreadMember (channelId, userId) {
|
|
982
1130
|
await rest.delete(rest.routes.channels.threads.user(channelId, userId));
|
|
983
1131
|
},
|
|
1132
|
+
async removeDmRecipient (channelId, userId) {
|
|
1133
|
+
await rest.delete(rest.routes.channels.dmRecipient(channelId, userId));
|
|
1134
|
+
},
|
|
984
1135
|
async sendFollowupMessage (token, options) {
|
|
985
1136
|
return await rest.post(rest.routes.webhooks.webhook(rest.applicationId, token), {
|
|
986
1137
|
body: options,
|
|
@@ -1038,6 +1189,14 @@ export function createRestManager(options) {
|
|
|
1038
1189
|
async getMember (guildId, userId) {
|
|
1039
1190
|
return await rest.get(rest.routes.guilds.members.member(guildId, userId));
|
|
1040
1191
|
},
|
|
1192
|
+
async getCurrentMember (guildId, token) {
|
|
1193
|
+
return await rest.get(rest.routes.guilds.members.currentMember(guildId), {
|
|
1194
|
+
headers: {
|
|
1195
|
+
authorization: `Bearer ${token}`
|
|
1196
|
+
},
|
|
1197
|
+
unauthorized: true
|
|
1198
|
+
});
|
|
1199
|
+
},
|
|
1041
1200
|
async getMembers (guildId, options) {
|
|
1042
1201
|
return await rest.get(rest.routes.guilds.members.members(guildId, options));
|
|
1043
1202
|
},
|
|
@@ -1073,15 +1232,62 @@ export function createRestManager(options) {
|
|
|
1073
1232
|
async triggerTypingIndicator (channelId) {
|
|
1074
1233
|
await rest.post(rest.routes.channels.typing(channelId));
|
|
1075
1234
|
},
|
|
1076
|
-
async upsertGlobalApplicationCommands (body) {
|
|
1077
|
-
|
|
1235
|
+
async upsertGlobalApplicationCommands (body, options) {
|
|
1236
|
+
const restOptions = {
|
|
1237
|
+
body
|
|
1238
|
+
};
|
|
1239
|
+
if (options?.bearerToken) {
|
|
1240
|
+
restOptions.unauthorized = true;
|
|
1241
|
+
restOptions.headers = {
|
|
1242
|
+
authorization: `Bearer ${options.bearerToken}`
|
|
1243
|
+
};
|
|
1244
|
+
}
|
|
1245
|
+
return await rest.put(rest.routes.interactions.commands.commands(rest.applicationId), restOptions);
|
|
1246
|
+
},
|
|
1247
|
+
async upsertGuildApplicationCommands (guildId, body, options) {
|
|
1248
|
+
const restOptions = {
|
|
1078
1249
|
body
|
|
1250
|
+
};
|
|
1251
|
+
if (options?.bearerToken) {
|
|
1252
|
+
restOptions.unauthorized = true;
|
|
1253
|
+
restOptions.headers = {
|
|
1254
|
+
authorization: `Bearer ${options.bearerToken}`
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
return await rest.put(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), restOptions);
|
|
1258
|
+
},
|
|
1259
|
+
async editUserApplicationRoleConnection (token, applicationId, body) {
|
|
1260
|
+
return await rest.put(rest.routes.oauth2.roleConnections(applicationId), {
|
|
1261
|
+
body,
|
|
1262
|
+
headers: {
|
|
1263
|
+
authorization: `Bearer ${token}`
|
|
1264
|
+
},
|
|
1265
|
+
unauthorized: true
|
|
1079
1266
|
});
|
|
1080
1267
|
},
|
|
1081
|
-
async
|
|
1082
|
-
return await rest.put(rest.routes.
|
|
1268
|
+
async addGuildMember (guildId, userId, body) {
|
|
1269
|
+
return await rest.put(rest.routes.guilds.members.member(guildId, userId), {
|
|
1083
1270
|
body
|
|
1084
1271
|
});
|
|
1272
|
+
},
|
|
1273
|
+
preferSnakeCase (enabled) {
|
|
1274
|
+
const camelizer = enabled ? (x)=>x : camelize;
|
|
1275
|
+
rest.get = async (url, options)=>{
|
|
1276
|
+
return camelizer(await rest.makeRequest('GET', url, options));
|
|
1277
|
+
};
|
|
1278
|
+
rest.post = async (url, options)=>{
|
|
1279
|
+
return camelizer(await rest.makeRequest('POST', url, options));
|
|
1280
|
+
};
|
|
1281
|
+
rest.delete = async (url, options)=>{
|
|
1282
|
+
camelizer(await rest.makeRequest('DELETE', url, options));
|
|
1283
|
+
};
|
|
1284
|
+
rest.patch = async (url, options)=>{
|
|
1285
|
+
return camelizer(await rest.makeRequest('PATCH', url, options));
|
|
1286
|
+
};
|
|
1287
|
+
rest.put = async (url, options)=>{
|
|
1288
|
+
return camelizer(await rest.makeRequest('PUT', url, options));
|
|
1289
|
+
};
|
|
1290
|
+
return rest;
|
|
1085
1291
|
}
|
|
1086
1292
|
};
|
|
1087
1293
|
return rest;
|