@discordeno/rest 19.0.0-next.40c19da → 19.0.0-next.4287398

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/manager.js CHANGED
@@ -1,510 +1,49 @@
1
- /* eslint-disable @typescript-eslint/restrict-template-expressions */ /* eslint-disable no-const-assign */ import { InteractionResponseTypes } from '@discordeno/types';
2
- import { calculateBits, camelize, camelToSnakeCase, delay, encode, findFiles, getBotIdFromToken, isGetMessagesAfter, isGetMessagesAround, isGetMessagesBefore, isGetMessagesLimit, logger, processReactionString, urlToBase64 } from '@discordeno/utils';
3
- import fetch from 'node-fetch';
1
+ /* eslint-disable @typescript-eslint/restrict-template-expressions */ /* eslint-disable no-const-assign */ import { Buffer } from 'node:buffer';
2
+ import { calculateBits, camelToSnakeCase, camelize, delay, getBotIdFromToken, logger, processReactionString, urlToBase64 } from '@discordeno/utils';
4
3
  import { createInvalidRequestBucket } from './invalidBucket.js';
5
4
  import { Queue } from './queue.js';
5
+ import { InteractionResponseTypes } from '@discordeno/types';
6
+ import { createRoutes } from './routes.js';
6
7
  // TODO: make dynamic based on package.json file
7
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';
8
18
  export function createRestManager(options) {
9
- // Falsy token string check
10
- if (!options.token) throw new Error('You must provide a valid token.');
19
+ const applicationId = options.applicationId ? BigInt(options.applicationId) : options.token ? getBotIdFromToken(options.token) : undefined;
20
+ if (!applicationId) {
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.');
22
+ }
23
+ const baseUrl = options.proxy?.baseUrl ?? DISCORD_API_URL;
11
24
  const rest = {
12
- token: options.token,
13
- applicationId: options.applicationId ? BigInt(options.applicationId) : getBotIdFromToken(options.token),
14
- version: options.version ?? 10,
15
- baseUrl: options.proxy?.baseUrl ?? 'https://discord.com/api',
16
- maxRetryCount: Infinity,
25
+ applicationId,
26
+ authorization: options.proxy?.authorization,
27
+ baseUrl,
28
+ deleteQueueDelay: 60000,
17
29
  globallyRateLimited: false,
30
+ invalidBucket: createInvalidRequestBucket({}),
31
+ isProxied: !baseUrl.startsWith(DISCORD_API_URL),
32
+ maxRetryCount: Infinity,
18
33
  processingRateLimitedPaths: false,
19
- deleteQueueDelay: 60000,
20
34
  queues: new Map(),
21
35
  rateLimitedPaths: new Map(),
22
- invalidBucket: createInvalidRequestBucket({}),
23
- authorization: options.proxy?.authorization,
24
- routes: {
25
- webhooks: {
26
- id: (webhookId)=>{
27
- return `/webhooks/${webhookId}`;
28
- },
29
- message: (webhookId, token, messageId, options)=>{
30
- let url = `/webhooks/${webhookId}/${token}/messages/${messageId}?`;
31
- if (options) {
32
- if (options.threadId) url += `thread_id=${options.threadId}`;
33
- }
34
- return url;
35
- },
36
- original: (webhookId, token, options)=>{
37
- let url = `/webhooks/${webhookId}/${token}/messages/@original?`;
38
- if (options) {
39
- if (options.threadId) url += `thread_id=${options.threadId}`;
40
- }
41
- return url;
42
- },
43
- webhook: (webhookId, token, options)=>{
44
- let url = `/webhooks/${webhookId}/${token}?`;
45
- if (options) {
46
- if (options?.wait !== undefined) url += `wait=${options.wait.toString()}`;
47
- if (options.threadId) url += `thread_id=${options.threadId}`;
48
- }
49
- return url;
50
- }
51
- },
52
- // Miscellaneous Endpoints
53
- sessionInfo: ()=>rest.routes.gatewayBot(),
54
- // Channel Endpoints
55
- channels: {
56
- bulk: (channelId)=>{
57
- return `/channels/${channelId}/messages/bulk-delete`;
58
- },
59
- dm: ()=>{
60
- return '/users/@me/channels';
61
- },
62
- pin: (channelId, messageId)=>{
63
- return `/channels/${channelId}/pins/${messageId}`;
64
- },
65
- pins: (channelId)=>{
66
- return `/channels/${channelId}/pins`;
67
- },
68
- reactions: {
69
- bot: (channelId, messageId, emoji)=>{
70
- return `/channels/${channelId}/messages/${messageId}/reactions/${encodeURIComponent(emoji)}/@me`;
71
- },
72
- user: (channelId, messageId, emoji, userId)=>{
73
- return `/channels/${channelId}/messages/${messageId}/reactions/${encodeURIComponent(emoji)}/${userId}`;
74
- },
75
- all: (channelId, messageId)=>{
76
- return `/channels/${channelId}/messages/${messageId}/reactions`;
77
- },
78
- emoji: (channelId, messageId, emoji, options)=>{
79
- let url = `/channels/${channelId}/messages/${messageId}/reactions/${encodeURIComponent(emoji)}?`;
80
- if (options) {
81
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
82
- if (options.after) url += `after=${options.after}`;
83
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
84
- if (options.limit) url += `&limit=${options.limit}`;
85
- }
86
- return url;
87
- },
88
- message: (channelId, messageId, emoji, options)=>{
89
- let url = `/channels/${channelId}/messages/${messageId}/reactions/${encodeURIComponent(emoji)}?`;
90
- if (options) {
91
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
92
- if (options.after) url += `after=${options.after}`;
93
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
94
- if (options.limit) url += `&limit=${options.limit}`;
95
- }
96
- return url;
97
- }
98
- },
99
- webhooks: (channelId)=>{
100
- return `/channels/${channelId}/webhooks`;
101
- },
102
- channel: (channelId)=>{
103
- return `/channels/${channelId}`;
104
- },
105
- follow: (channelId)=>{
106
- return `/channels/${channelId}/followers`;
107
- },
108
- forum: (channelId)=>{
109
- return `/channels/${channelId}/threads?has_message=true`;
110
- },
111
- invites: (channelId)=>{
112
- return `/channels/${channelId}/invites`;
113
- },
114
- message: (channelId, messageId)=>{
115
- return `/channels/${channelId}/messages/${messageId}`;
116
- },
117
- messages: (channelId, options)=>{
118
- let url = `/channels/${channelId}/messages?`;
119
- if (options) {
120
- if (isGetMessagesAfter(options) && options.after) {
121
- url += `after=${options.after}`;
122
- }
123
- if (isGetMessagesBefore(options) && options.before) {
124
- url += `&before=${options.before}`;
125
- }
126
- if (isGetMessagesAround(options) && options.around) {
127
- url += `&around=${options.around}`;
128
- }
129
- if (isGetMessagesLimit(options) && options.limit) {
130
- url += `&limit=${options.limit}`;
131
- }
132
- }
133
- return url;
134
- },
135
- overwrite: (channelId, overwriteId)=>{
136
- return `/channels/${channelId}/permissions/${overwriteId}`;
137
- },
138
- crosspost: (channelId, messageId)=>{
139
- return `/channels/${channelId}/messages/${messageId}/crosspost`;
140
- },
141
- stages: ()=>{
142
- return '/stage-instances';
143
- },
144
- stage: (channelId)=>{
145
- return `/stage-instances/${channelId}`;
146
- },
147
- // Thread Endpoints
148
- threads: {
149
- message: (channelId, messageId)=>{
150
- return `/channels/${channelId}/messages/${messageId}/threads`;
151
- },
152
- all: (channelId)=>{
153
- return `/channels/${channelId}/threads`;
154
- },
155
- active: (guildId)=>{
156
- return `/guilds/${guildId}/threads/active`;
157
- },
158
- members: (channelId)=>{
159
- return `/channels/${channelId}/thread-members`;
160
- },
161
- me: (channelId)=>{
162
- return `/channels/${channelId}/thread-members/@me`;
163
- },
164
- user: (channelId, userId)=>{
165
- return `/channels/${channelId}/thread-members/${userId}`;
166
- },
167
- archived: (channelId)=>{
168
- return `/channels/${channelId}/threads/archived`;
169
- },
170
- public: (channelId, options)=>{
171
- let url = `/channels/${channelId}/threads/archived/public?`;
172
- if (options) {
173
- if (options.before) {
174
- url += `before=${new Date(options.before).toISOString()}`;
175
- }
176
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
177
- if (options.limit) url += `&limit=${options.limit}`;
178
- }
179
- return url;
180
- },
181
- private: (channelId, options)=>{
182
- let url = `/channels/${channelId}/threads/archived/private?`;
183
- if (options) {
184
- if (options.before) {
185
- url += `before=${new Date(options.before).toISOString()}`;
186
- }
187
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
188
- if (options.limit) url += `&limit=${options.limit}`;
189
- }
190
- return url;
191
- },
192
- joined: (channelId, options)=>{
193
- let url = `/channels/${channelId}/users/@me/threads/archived/private?`;
194
- if (options) {
195
- if (options.before) {
196
- url += `before=${new Date(options.before).toISOString()}`;
197
- }
198
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
199
- if (options.limit) url += `&limit=${options.limit}`;
200
- }
201
- return url;
202
- }
203
- },
204
- typing: (channelId)=>{
205
- return `/channels/${channelId}/typing`;
206
- }
207
- },
208
- // Guild Endpoints
209
- guilds: {
210
- all: ()=>{
211
- return '/guilds';
212
- },
213
- auditlogs: (guildId, options)=>{
214
- let url = `/guilds/${guildId}/audit-logs?`;
215
- if (options) {
216
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
217
- if (options.actionType) url += `action_type=${options.actionType}`;
218
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
219
- if (options.before) url += `&before=${options.before}`;
220
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
221
- if (options.limit) url += `&limit=${options.limit}`;
222
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
223
- if (options.userId) url += `&user_id=${options.userId}`;
224
- }
225
- return url;
226
- },
227
- automod: {
228
- rule: (guildId, ruleId)=>{
229
- return `/guilds/${guildId}/auto-moderation/rules/${ruleId}`;
230
- },
231
- rules: (guildId)=>{
232
- return `/guilds/${guildId}/auto-moderation/rules`;
233
- }
234
- },
235
- channels: (guildId)=>{
236
- return `/guilds/${guildId}/channels`;
237
- },
238
- emoji: (guildId, emojiId)=>{
239
- return `/guilds/${guildId}/emojis/${emojiId}`;
240
- },
241
- emojis: (guildId)=>{
242
- return `/guilds/${guildId}/emojis`;
243
- },
244
- events: {
245
- events: (guildId, withUserCount)=>{
246
- let url = `/guilds/${guildId}/scheduled-events?`;
247
- if (withUserCount !== undefined) {
248
- url += `with_user_count=${withUserCount.toString()}`;
249
- }
250
- return url;
251
- },
252
- event: (guildId, eventId, withUserCount)=>{
253
- let url = `/guilds/${guildId}/scheduled-events/${eventId}`;
254
- if (withUserCount !== undefined) {
255
- url += `with_user_count=${withUserCount.toString()}`;
256
- }
257
- return url;
258
- },
259
- users: (guildId, eventId, options)=>{
260
- let url = `/guilds/${guildId}/scheduled-events/${eventId}/users?`;
261
- if (options) {
262
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
263
- if (options.limit !== undefined) url += `limit=${options.limit}`;
264
- if (options.withMember !== undefined) {
265
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
266
- url += `&with_member=${options.withMember.toString()}`;
267
- }
268
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
269
- if (options.after !== undefined) url += `&after=${options.after}`;
270
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
271
- if (options.before !== undefined) url += `&before=${options.before}`;
272
- }
273
- return url;
274
- }
275
- },
276
- guild (guildId, withCounts) {
277
- let url = `/guilds/${guildId}?`;
278
- if (withCounts !== undefined) {
279
- url += `with_counts=${withCounts.toString()}`;
280
- }
281
- return url;
282
- },
283
- integration (guildId, integrationId) {
284
- return `/guilds/${guildId}/integrations/${integrationId}`;
285
- },
286
- integrations: (guildId)=>{
287
- return `/guilds/${guildId}/integrations?include_applications=true`;
288
- },
289
- invite (inviteCode, options) {
290
- let url = `/invites/${inviteCode}?`;
291
- if (options) {
292
- if (options.withCounts !== undefined) {
293
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
294
- url += `with_counts=${options.withCounts.toString()}`;
295
- }
296
- if (options.withExpiration !== undefined) {
297
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
298
- url += `&with_expiration=${options.withExpiration.toString()}`;
299
- }
300
- if (options.scheduledEventId) {
301
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
302
- url += `&guild_scheduled_event_id=${options.scheduledEventId}`;
303
- }
304
- }
305
- return url;
306
- },
307
- invites: (guildId)=>{
308
- return `/guilds/${guildId}/invites`;
309
- },
310
- leave: (guildId)=>{
311
- return `/users/@me/guilds/${guildId}`;
312
- },
313
- members: {
314
- ban: (guildId, userId)=>{
315
- return `/guilds/${guildId}/bans/${userId}`;
316
- },
317
- bans: (guildId, options)=>{
318
- let url = `/guilds/${guildId}/bans?`;
319
- if (options) {
320
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
321
- if (options.limit) url += `limit=${options.limit}`;
322
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
323
- if (options.after) url += `&after=${options.after}`;
324
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
325
- if (options.before) url += `&before=${options.before}`;
326
- }
327
- return url;
328
- },
329
- bot: (guildId)=>{
330
- return `/guilds/${guildId}/members/@me`;
331
- },
332
- member: (guildId, userId)=>{
333
- return `/guilds/${guildId}/members/${userId}`;
334
- },
335
- members: (guildId, options)=>{
336
- let url = `/guilds/${guildId}/members?`;
337
- if (options !== undefined) {
338
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
339
- if (options.limit) url += `limit=${options.limit}`;
340
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
341
- if (options.after) url += `&after=${options.after}`;
342
- }
343
- return url;
344
- },
345
- search: (guildId, query, options)=>{
346
- let url = `/guilds/${guildId}/members/search?query=${encodeURIComponent(query)}`;
347
- if (options) {
348
- if (options.limit !== undefined) url += `&limit=${options.limit}`;
349
- }
350
- return url;
351
- },
352
- prune: (guildId, options)=>{
353
- let url = `/guilds/${guildId}/prune?`;
354
- if (options) {
355
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
356
- if (options.days) url += `days=${options.days}`;
357
- if (Array.isArray(options.includeRoles)) {
358
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
359
- url += `&include_roles=${options.includeRoles.join(',')}`;
360
- } else if (options.includeRoles) {
361
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
362
- url += `&include_roles=${options.includeRoles}`;
363
- }
364
- }
365
- return url;
366
- }
367
- },
368
- mfa: (guildId)=>`/guilds/${guildId}/mfa`,
369
- preview: (guildId)=>{
370
- return `/guilds/${guildId}/preview`;
371
- },
372
- prune: (guildId, options)=>{
373
- let url = `/guilds/${guildId}/prune?`;
374
- if (options) {
375
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
376
- if (options.days) url += `days=${options.days}`;
377
- if (Array.isArray(options.includeRoles)) {
378
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
379
- url += `&include_roles=${options.includeRoles.join(',')}`;
380
- } else if (options.includeRoles) {
381
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
382
- url += `&include_roles=${options.includeRoles}`;
383
- }
384
- }
385
- return url;
386
- },
387
- roles: {
388
- one: (guildId, roleId)=>{
389
- return `/guilds/${guildId}/roles/${roleId}`;
390
- },
391
- all: (guildId)=>{
392
- return `/guilds/${guildId}/roles`;
393
- },
394
- member: (guildId, memberId, roleId)=>{
395
- return `/guilds/${guildId}/members/${memberId}/roles/${roleId}`;
396
- }
397
- },
398
- stickers: (guildId)=>{
399
- return `/guilds/${guildId}/stickers`;
400
- },
401
- sticker: (guildId, stickerId)=>{
402
- return `/guilds/${guildId}/stickers/${stickerId}`;
403
- },
404
- voice: (guildId, userId)=>{
405
- return `/guilds/${guildId}/voice-states/${userId ?? '@me'}`;
406
- },
407
- templates: {
408
- code: (code)=>{
409
- return `/guilds/templates/${code}`;
410
- },
411
- guild: (guildId, code)=>{
412
- return `/guilds/${guildId}/templates/${code}`;
413
- },
414
- all: (guildId)=>{
415
- return `/guilds/${guildId}/templates`;
416
- }
417
- },
418
- vanity: (guildId)=>{
419
- return `/guilds/${guildId}/vanity-url`;
420
- },
421
- regions: (guildId)=>{
422
- return `/guilds/${guildId}/regions`;
423
- },
424
- webhooks: (guildId)=>{
425
- return `/guilds/${guildId}/webhooks`;
426
- },
427
- welcome: (guildId)=>{
428
- return `/guilds/${guildId}/welcome-screen`;
429
- },
430
- widget: (guildId)=>{
431
- return `/guilds/${guildId}/widget`;
432
- },
433
- widgetJson: (guildId)=>{
434
- return `/guilds/${guildId}/widget.json`;
435
- }
436
- },
437
- sticker: (stickerId)=>{
438
- return `/stickers/${stickerId}`;
439
- },
440
- regions: ()=>{
441
- return '/voice/regions';
442
- },
443
- // Interaction Endpoints
444
- interactions: {
445
- commands: {
446
- // Application Endpoints
447
- commands: (applicationId)=>{
448
- return `/applications/${applicationId}/commands`;
449
- },
450
- guilds: {
451
- all (applicationId, guildId) {
452
- return `/applications/${applicationId}/guilds/${guildId}/commands`;
453
- },
454
- one (applicationId, guildId, commandId, withLocalizations) {
455
- let url = `/applications/${applicationId}/guilds/${guildId}/commands/${commandId}?`;
456
- if (withLocalizations !== undefined) {
457
- url += `with_localizations=${withLocalizations.toString()}`;
458
- }
459
- return url;
460
- }
461
- },
462
- permissions: (applicationId, guildId)=>{
463
- return `/applications/${applicationId}/guilds/${guildId}/commands/permissions`;
464
- },
465
- permission: (applicationId, guildId, commandId)=>{
466
- return `/applications/${applicationId}/guilds/${guildId}/commands/${commandId}/permissions`;
467
- },
468
- command: (applicationId, commandId, withLocalizations)=>{
469
- let url = `/applications/${applicationId}/commands/${commandId}?`;
470
- if (withLocalizations !== undefined) {
471
- url += `withLocalizations=${withLocalizations.toString()}`;
472
- }
473
- return url;
474
- }
475
- },
476
- responses: {
477
- // Interaction Endpoints
478
- callback: (interactionId, token)=>{
479
- return `/interactions/${interactionId}/${token}/callback`;
480
- },
481
- original: (interactionId, token)=>{
482
- return `/webhooks/${interactionId}/${token}/messages/@original`;
483
- },
484
- message: (applicationId, token, messageId)=>{
485
- return `/webhooks/${applicationId}/${token}/messages/${messageId}`;
486
- }
487
- }
488
- },
489
- // User endpoints
490
- user (userId) {
491
- return `/users/${userId}`;
492
- },
493
- userBot () {
494
- return '/users/@me';
495
- },
496
- oauth2Application () {
497
- return 'oauth2/applications/@me';
498
- },
499
- gatewayBot () {
500
- return '/gateway/bot';
501
- },
502
- nitroStickerPacks () {
503
- return '/sticker-packs';
504
- }
36
+ token: options.token,
37
+ version: options.version ?? DISCORD_API_VERSION,
38
+ routes: createRoutes(),
39
+ createBaseHeaders () {
40
+ return {
41
+ 'user-agent': `DiscordBot (https://github.com/discordeno/discordeno, v${version})`
42
+ };
505
43
  },
506
- checkRateLimits (url) {
507
- const ratelimited = rest.rateLimitedPaths.get(url);
44
+ checkRateLimits (url, headers) {
45
+ const authHeader = headers?.authorization ?? '';
46
+ const ratelimited = rest.rateLimitedPaths.get(`${authHeader}${url}`);
508
47
  const global = rest.rateLimitedPaths.get('global');
509
48
  const now = Date.now();
510
49
  if (ratelimited && now < ratelimited.resetTimestamp) {
@@ -523,76 +62,81 @@ export function createRestManager(options) {
523
62
  }
524
63
  const newObj = {};
525
64
  for (const key of Object.keys(obj)){
526
- // Keys that dont require snake casing
527
- if ([
528
- 'permissions',
529
- 'allow',
530
- 'deny'
531
- ].includes(key)) {
532
- newObj[key] = calculateBits(obj[key]);
533
- continue;
534
- }
535
- if (key === 'defaultMemberPermissions') {
536
- newObj.default_member_permissions = calculateBits(obj[key]);
537
- continue;
65
+ const value = obj[key];
66
+ // Some falsy values should be allowed like null or 0
67
+ if (value !== undefined) {
68
+ switch(key){
69
+ case 'permissions':
70
+ case 'allow':
71
+ case 'deny':
72
+ newObj[key] = typeof value === 'string' ? value : calculateBits(value);
73
+ continue;
74
+ case 'defaultMemberPermissions':
75
+ newObj.default_member_permissions = typeof value === 'string' ? value : calculateBits(value);
76
+ continue;
77
+ case 'nameLocalizations':
78
+ newObj.name_localizations = value;
79
+ continue;
80
+ case 'descriptionLocalizations':
81
+ newObj.description_localizations = value;
82
+ continue;
83
+ }
538
84
  }
539
- newObj[camelToSnakeCase(key)] = rest.changeToDiscordFormat(obj[key]);
85
+ newObj[camelToSnakeCase(key)] = rest.changeToDiscordFormat(value);
540
86
  }
541
87
  return newObj;
542
88
  }
543
89
  if (typeof obj === 'bigint') return obj.toString();
544
90
  return obj;
545
91
  },
546
- createRequest (options) {
547
- const headers = {
548
- 'user-agent': `DiscordBot (https://github.com/discordeno/discordeno, v${version})`
549
- };
550
- if (!options.unauthorized) headers.authorization = `Bot ${rest.token}`;
551
- // SOMETIMES SPECIAL HEADERS (E.G. CUSTOM AUTHORIZATION) NEED TO BE USED
552
- if (options.headers) {
553
- for(const key in options.headers){
554
- headers[key.toLowerCase()] = options.headers[key];
555
- }
556
- }
557
- // GET METHODS SHOULD NOT HAVE A BODY
558
- if (options.method === 'GET') {
559
- options.body = undefined;
560
- }
92
+ createRequestBody (method, options) {
93
+ const headers = this.createBaseHeaders();
94
+ if (options?.unauthorized !== true) headers.authorization = `Bot ${rest.token}`;
561
95
  // IF A REASON IS PROVIDED ENCODE IT IN HEADERS
562
- if (options.body?.reason) {
563
- headers['X-Audit-Log-Reason'] = encodeURIComponent(options.body.reason);
564
- options.body.reason = undefined;
96
+ if (options?.reason !== undefined) {
97
+ headers[AUDIT_LOG_REASON_HEADER] = encodeURIComponent(options?.reason);
565
98
  }
566
- if (options.body) {
567
- const { file } = options.body;
568
- if (file) {
569
- const files = findFiles(file);
570
- const form = new FormData();
571
- // WHEN CREATING A STICKER, DISCORD WANTS FORM DATA ONLY
572
- if (options.url?.endsWith('/stickers') && options.method === 'POST') {
573
- form.append('file', files[0].blob, files[0].name);
574
- form.append('name', options.body.name);
575
- form.append('description', options.body.description);
576
- form.append('tags', options.body.tags);
577
- } else {
578
- for(let i = 0; i < files.length; i++){
579
- form.append(`file${i}`, files[i].blob, files[i].name);
580
- }
581
- if (file) options.body.file = undefined;
582
- form.append('payload_json', JSON.stringify(rest.changeToDiscordFormat(options.body)));
583
- }
584
- options.body.file = form;
585
- } else if (options.body && ![
586
- 'GET',
587
- 'DELETE'
588
- ].includes(options.method)) {
589
- headers['Content-Type'] = 'application/json';
99
+ let body;
100
+ // TODO: check if we need to add specific check for GET method
101
+ // Since GET does not allow bodies
102
+ // Have to check for attachments first, since body then has to be send in a different way.
103
+ if (options?.files !== undefined) {
104
+ const form = new FormData();
105
+ for(let i = 0; i < options.files.length; ++i){
106
+ form.append(`file${i}`, options.files[i].blob, options.files[i].name);
107
+ }
108
+ // Have to use changeToDiscordFormat or else JSON.stringify may throw an error for the presence of BigInt(s) in the json
109
+ form.append('payload_json', JSON.stringify(rest.changeToDiscordFormat({
110
+ ...options.body,
111
+ files: undefined
112
+ })));
113
+ // No need to set the `content-type` header since `fetch` does that automatically for us when we use a `FormData` object.
114
+ body = form;
115
+ } else if (options?.body && options.headers && options.headers['content-type'] === 'application/x-www-form-urlencoded') {
116
+ // OAuth2 body handling
117
+ const formBody = [];
118
+ const discordBody = rest.changeToDiscordFormat(options.body);
119
+ for(const prop in discordBody){
120
+ formBody.push(`${encodeURIComponent(prop)}=${encodeURIComponent(discordBody[prop])}`);
121
+ }
122
+ body = formBody.join('&');
123
+ } else if (options?.body !== undefined) {
124
+ if (options.body instanceof FormData) {
125
+ body = options.body;
126
+ // No need to set the `content-type` header since `fetch` does that automatically for us when we use a `FormData` object.
127
+ } else {
128
+ body = JSON.stringify(rest.changeToDiscordFormat(options.body));
129
+ headers['content-type'] = `application/json`;
590
130
  }
591
131
  }
132
+ // SOMETIMES SPECIAL HEADERS (E.G. CUSTOM AUTHORIZATION) NEED TO BE USED
133
+ if (options?.headers) {
134
+ Object.assign(headers, options.headers);
135
+ }
592
136
  return {
137
+ body,
593
138
  headers,
594
- body: options.body?.file ?? JSON.stringify(rest.changeToDiscordFormat(options.body)),
595
- method: options.method
139
+ method
596
140
  };
597
141
  },
598
142
  processRateLimitedPaths () {
@@ -622,17 +166,17 @@ export function createRestManager(options) {
622
166
  }, 1000);
623
167
  }
624
168
  },
625
- /** Processes the rate limit headers and determines if it needs to be rate limited and returns the bucket id if available */ processHeaders (url, headers) {
169
+ /** 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) {
626
170
  let rateLimited = false;
627
171
  // GET ALL NECESSARY HEADERS
628
- const remaining = headers.get('x-ratelimit-remaining');
629
- const retryAfter = headers.get('x-ratelimit-reset-after');
172
+ const remaining = headers.get(RATE_LIMIT_REMAINING_HEADER);
173
+ const retryAfter = headers.get(RATE_LIMIT_RESET_AFTER_HEADER);
630
174
  const reset = Date.now() + Number(retryAfter) * 1000;
631
- const global = headers.get('x-ratelimit-global');
175
+ const global = headers.get(RATE_LIMIT_GLOBAL_HEADER);
632
176
  // undefined override null needed for typings
633
- const bucketId = headers.get('x-ratelimit-bucket') ?? undefined;
634
- const limit = headers.get('x-ratelimit-limit');
635
- rest.queues.get(url)?.handleCompletedRequest({
177
+ const bucketId = headers.get(RATE_LIMIT_BUCKET_HEADER) ?? undefined;
178
+ const limit = headers.get(RATE_LIMIT_LIMIT_HEADER);
179
+ rest.queues.get(`${requestAuthorization}${url}`)?.handleCompletedRequest({
636
180
  remaining: remaining ? Number(remaining) : undefined,
637
181
  interval: retryAfter ? Number(retryAfter) * 1000 : undefined,
638
182
  max: limit ? Number(limit) : undefined
@@ -641,14 +185,14 @@ export function createRestManager(options) {
641
185
  if (remaining === '0') {
642
186
  rateLimited = true;
643
187
  // SAVE THE URL AS LIMITED, IMPORTANT FOR NEW REQUESTS BY USER WITHOUT BUCKET
644
- rest.rateLimitedPaths.set(url, {
188
+ rest.rateLimitedPaths.set(`${requestAuthorization}${url}`, {
645
189
  url,
646
190
  resetTimestamp: reset,
647
191
  bucketId
648
192
  });
649
193
  // SAVE THE BUCKET AS LIMITED SINCE DIFFERENT URLS MAY SHARE A BUCKET
650
194
  if (bucketId) {
651
- rest.rateLimitedPaths.set(bucketId, {
195
+ rest.rateLimitedPaths.set(`${requestAuthorization}${bucketId}`, {
652
196
  url,
653
197
  resetTimestamp: reset,
654
198
  bucketId
@@ -657,8 +201,8 @@ export function createRestManager(options) {
657
201
  }
658
202
  // IF THERE IS NO REMAINING GLOBAL LIMIT, MARK IT RATE LIMITED GLOBALLY
659
203
  if (global) {
660
- const retryAfter = headers.get('retry-after');
661
- const globalReset = Date.now() + Number(retryAfter) * 1000;
204
+ const retryAfter = Number(headers.get('retry-after')) * 1000;
205
+ const globalReset = Date.now() + retryAfter;
662
206
  // rest.debug(
663
207
  // `[REST = Globally Rate Limited] URL: ${url} | Global Rest: ${globalReset}`
664
208
  // )
@@ -666,14 +210,14 @@ export function createRestManager(options) {
666
210
  rateLimited = true;
667
211
  setTimeout(()=>{
668
212
  rest.globallyRateLimited = false;
669
- }, globalReset);
213
+ }, retryAfter);
670
214
  rest.rateLimitedPaths.set('global', {
671
215
  url: 'global',
672
216
  resetTimestamp: globalReset,
673
217
  bucketId
674
218
  });
675
219
  if (bucketId) {
676
- rest.rateLimitedPaths.set(bucketId, {
220
+ rest.rateLimitedPaths.set(`${requestAuthorization}${bucketId}`, {
677
221
  url: 'global',
678
222
  resetTimestamp: globalReset,
679
223
  bucketId
@@ -686,138 +230,124 @@ export function createRestManager(options) {
686
230
  return rateLimited ? bucketId : undefined;
687
231
  },
688
232
  async sendRequest (options) {
689
- const url = options.url.startsWith('https://') ? options.url : `${rest.baseUrl}/v${rest.version}${options.url}`;
690
- const payload = rest.createRequest({
691
- method: options.method,
692
- url: options.url,
693
- body: options.body,
694
- ...options.options
695
- });
233
+ const url = `${rest.baseUrl}/v${rest.version}${options.route}`;
234
+ const payload = rest.createRequestBody(options.method, options.requestBodyOptions);
235
+ const loggingHeaders = {
236
+ ...payload.headers
237
+ };
238
+ const authenticationScheme = payload.headers.authorization?.split(' ')[0];
239
+ if (payload.headers.authorization) {
240
+ loggingHeaders.authorization = `${authenticationScheme} tokenhere`;
241
+ }
696
242
  logger.debug(`sending request to ${url}`, 'with payload:', {
697
243
  ...payload,
698
- headers: {
699
- ...payload.headers,
700
- authorization: 'Bot tokenhere'
701
- }
244
+ headers: loggingHeaders
245
+ });
246
+ const response = await fetch(url, payload).catch(async (error)=>{
247
+ logger.error(error);
248
+ // Mark request and completed
249
+ rest.invalidBucket.handleCompletedRequest(999, false);
250
+ options.reject({
251
+ ok: false,
252
+ status: 999,
253
+ error: 'Possible network or request shape issue occurred. If this is rare, its a network glitch. If it occurs a lot something is wrong.'
254
+ });
255
+ throw error;
702
256
  });
703
- const response = await fetch(url, payload);
704
257
  logger.debug(`request fetched from ${url} with status ${response.status} & ${response.statusText}`);
258
+ // Mark request and completed
259
+ rest.invalidBucket.handleCompletedRequest(response.status, response.headers.get(RATE_LIMIT_SCOPE_HEADER) === 'shared');
705
260
  // Set the bucket id if it was available on the headers
706
- const bucketId = rest.processHeaders(rest.simplifyUrl(options.url, options.method), response.headers);
261
+ const bucketId = rest.processHeaders(rest.simplifyUrl(options.route, options.method), response.headers, authenticationScheme === 'Bearer' ? payload.headers.authorization : '');
707
262
  if (bucketId) options.bucketId = bucketId;
708
263
  if (response.status < 200 || response.status >= 400) {
709
264
  logger.debug(`Request to ${url} failed.`);
710
- if (response.status === 429) {
711
- logger.debug(`Request to ${url} was ratelimited.`);
712
- // Too many attempts, get rid of request from queue.
713
- if (options.retryCount++ >= rest.maxRetryCount) {
714
- logger.debug(`Request to ${url} exceeded the maximum allowed retries.`, 'with payload:', payload);
715
- // rest.debug(`[REST - RetriesMaxed] ${JSON.stringify(options)}`)
716
- // Remove item from queue to prevent retry
717
- options.reject({
718
- ok: false,
719
- status: response.status,
720
- error: 'The options was rate limited and it maxed out the retries limit.'
721
- });
722
- return;
723
- }
724
- // Rate limited, add back to queue
725
- rest.invalidBucket.handleCompletedRequest(response.status, response.headers.get('X-RateLimit-Scope') === 'shared');
726
- const resetAfter = response.headers.get('x-ratelimit-reset-after');
727
- if (resetAfter) await delay(Number(resetAfter) * 1000);
728
- // process the response to prevent mem leak
729
- await response.json();
730
- return await options.retryRequest?.(options);
265
+ if (response.status !== 429) {
266
+ options.reject({
267
+ ok: false,
268
+ status: response.status,
269
+ body: await response.text()
270
+ });
271
+ return;
731
272
  }
732
- options.reject({
733
- ok: false,
734
- status: response.status,
735
- body: JSON.stringify(await response.json())
736
- });
737
- return;
273
+ logger.debug(`Request to ${url} was ratelimited.`);
274
+ // Too many attempts, get rid of request from queue.
275
+ if (options.retryCount >= rest.maxRetryCount) {
276
+ logger.debug(`Request to ${url} exceeded the maximum allowed retries.`, 'with payload:', payload);
277
+ // rest.debug(`[REST - RetriesMaxed] ${JSON.stringify(options)}`)
278
+ options.reject({
279
+ ok: false,
280
+ status: response.status,
281
+ error: 'The request was rate limited and it maxed out the retries limit.'
282
+ });
283
+ return;
284
+ }
285
+ options.retryCount += 1;
286
+ const resetAfter = response.headers.get(RATE_LIMIT_RESET_AFTER_HEADER);
287
+ if (resetAfter) await delay(Number(resetAfter) * 1000);
288
+ // process the response to prevent mem leak
289
+ await response.arrayBuffer();
290
+ return await options.retryRequest?.(options);
738
291
  }
739
- const is204 = response.status === 204;
740
- const json = is204 ? undefined : await response.json();
741
- // Discord sometimes sends no response with 204 code
292
+ // Discord sometimes sends no response with no content.
742
293
  options.resolve({
743
294
  ok: true,
744
295
  status: response.status,
745
- body: JSON.stringify(json)
296
+ body: response.status === 204 ? undefined : await response.text()
746
297
  });
747
298
  },
748
- // Credits: github.com/abalabahaha/eris lib/rest/RequestHandler.js#L397
749
- // Modified for our use-case
750
299
  simplifyUrl (url, method) {
751
- let route = url.replace(/\/([a-z-]+)\/(?:[0-9]{17,19})/g, function(match, p) {
752
- return [
753
- 'channels',
754
- 'guilds'
755
- ].includes(p) ? match : `/${p}/x`;
756
- }).replace(/\/reactions\/[^/]+/g, '/reactions/x');
757
- // GENERAL /reactions and /reactions/emoji/@me share the buckets
758
- if (route.includes('/reactions')) {
759
- route = route.substring(0, route.indexOf('/reactions') + '/reactions'.length);
300
+ const parts = url.split('/');
301
+ const secondLastPart = parts[parts.length - 2];
302
+ if (secondLastPart === 'channels' || secondLastPart === 'guilds') {
303
+ return url;
304
+ }
305
+ if (secondLastPart === 'reactions' || parts[parts.length - 1] === '@me') {
306
+ parts.splice(-2);
307
+ parts.push('reactions');
308
+ } else {
309
+ parts.splice(-1);
310
+ parts.push('x');
311
+ }
312
+ if (parts[parts.length - 3] === 'reactions') {
313
+ parts.splice(-2);
760
314
  }
761
- // Delete Message endpoint has its own rate limit
762
- if (method === 'DELETE' && route.endsWith('/messages/x')) {
763
- route = method + route;
315
+ if (method === 'DELETE' && secondLastPart === 'messages') {
316
+ return `D${parts.join('/')}`;
764
317
  }
765
- return route;
766
- },
767
- processRequest (request) {
768
- const route = request.url.substring(request.url.indexOf('api/'));
769
- const parts = route.split('/');
770
- // Remove the api/
771
- parts.shift();
772
- // Removes the /v#/
773
- if (parts[0]?.startsWith('v')) parts.shift();
774
- // Set the full url to discord api in case it was recieved in a proxy rest
775
- request.url = `${rest.baseUrl}/v${rest.version}/${parts.join('/')}`;
776
- const url = rest.simplifyUrl(request.url, request.method);
777
- const queue = rest.queues.get(url);
318
+ return parts.join('/');
319
+ },
320
+ async processRequest (request) {
321
+ const url = rest.simplifyUrl(request.route, request.method);
322
+ if (request.runThroughQueue === false) {
323
+ await rest.sendRequest(request);
324
+ return;
325
+ }
326
+ const authHeader = request.requestBodyOptions?.headers?.authorization ?? '';
327
+ const queue = rest.queues.get(`${authHeader}${url}`);
778
328
  if (queue !== undefined) {
779
329
  queue.makeRequest(request);
780
330
  } else {
781
331
  // CREATES A NEW QUEUE
782
332
  const bucketQueue = new Queue(rest, {
783
333
  url,
784
- deleteQueueDelay: rest.deleteQueueDelay
334
+ deleteQueueDelay: rest.deleteQueueDelay,
335
+ authentication: authHeader
785
336
  });
786
337
  // Add request to queue
787
338
  bucketQueue.makeRequest(request);
788
339
  // Save queue
789
- rest.queues.set(url, bucketQueue);
340
+ rest.queues.set(`${authHeader}${url}`, bucketQueue);
790
341
  }
791
342
  },
792
- async makeRequest (method, url, body, options) {
793
- if (!rest.baseUrl.startsWith('https://discord.com') && url[0] === '/') {
794
- // Special handling for sending blobs across http to proxy
795
- if (body?.file) {
796
- if (!Array.isArray(body.file)) {
797
- body.file = [
798
- body.file
799
- ];
800
- }
801
- // convert blobs to string before sending to proxy
802
- body.file = await Promise.all(body.file.map(async (f)=>{
803
- const url = encode(await f.blob.arrayBuffer());
804
- return {
805
- name: f.name,
806
- blob: `data:${f.blob.type};base64,${url}`
807
- };
808
- }));
809
- }
810
- const headers = {
811
- Authorization: rest.authorization ?? ""
812
- };
813
- if (body) {
814
- headers['Content-Type'] = 'application/json';
343
+ async makeRequest (method, route, options) {
344
+ if (rest.isProxied) {
345
+ if (rest.authorization !== undefined) {
346
+ options ??= {};
347
+ options.headers ??= {};
348
+ options.headers.authorization = rest.authorization;
815
349
  }
816
- const result = await fetch(`${rest.baseUrl}${url}`, {
817
- body: body ? JSON.stringify(body) : undefined,
818
- headers,
819
- method
820
- });
350
+ const result = await fetch(`${rest.baseUrl}/v${rest.version}${route}`, rest.createRequestBody(method, options));
821
351
  if (!result.ok) {
822
352
  const err = await result.json().catch(()=>{});
823
353
  // Legacy Handling to not break old code or when body is missing
@@ -826,38 +356,39 @@ export function createRestManager(options) {
826
356
  }
827
357
  return result.status !== 204 ? await result.json() : undefined;
828
358
  }
829
- return await new Promise((resolve, reject)=>{
359
+ // eslint-disable-next-line no-async-promise-executor
360
+ return await new Promise(async (resolve, reject)=>{
830
361
  const payload = {
831
- url,
362
+ route,
832
363
  method,
833
- body,
364
+ requestBodyOptions: options,
834
365
  retryCount: 0,
835
- retryRequest: async function(options) {
836
- rest.processRequest(payload);
366
+ retryRequest: async function(payload) {
367
+ await rest.processRequest(payload);
837
368
  },
838
369
  resolve: (data)=>{
839
370
  resolve(data.status !== 204 ? JSON.parse(data.body ?? '{}') : undefined);
840
371
  },
841
372
  reject,
842
- options
373
+ runThroughQueue: options?.runThroughQueue
843
374
  };
844
- rest.processRequest(payload);
375
+ await rest.processRequest(payload);
845
376
  });
846
377
  },
847
- async get (url) {
848
- return camelize(await rest.makeRequest('GET', url));
378
+ async get (url, options) {
379
+ return camelize(await rest.makeRequest('GET', url, options));
849
380
  },
850
- async post (url, body) {
851
- return camelize(await rest.makeRequest('POST', url, body));
381
+ async post (url, options) {
382
+ return camelize(await rest.makeRequest('POST', url, options));
852
383
  },
853
- async delete (url, body) {
854
- camelize(await rest.makeRequest('DELETE', url, body));
384
+ async delete (url, options) {
385
+ camelize(await rest.makeRequest('DELETE', url, options));
855
386
  },
856
- async patch (url, body) {
857
- return camelize(await rest.makeRequest('PATCH', url, body));
387
+ async patch (url, options) {
388
+ return camelize(await rest.makeRequest('PATCH', url, options));
858
389
  },
859
- async put (url, body, options) {
860
- return camelize(await rest.makeRequest('PUT', url, body, options));
390
+ async put (url, options) {
391
+ return camelize(await rest.makeRequest('PUT', url, options));
861
392
  },
862
393
  async addReaction (channelId, messageId, reaction) {
863
394
  reaction = processReactionString(reaction);
@@ -882,59 +413,120 @@ export function createRestManager(options) {
882
413
  async addThreadMember (channelId, userId) {
883
414
  await rest.put(rest.routes.channels.threads.user(channelId, userId));
884
415
  },
885
- async createAutomodRule (guildId, options) {
886
- return await rest.post(rest.routes.guilds.automod.rules(guildId), options);
416
+ async addDmRecipient (channelId, userId, body) {
417
+ await rest.put(rest.routes.channels.dmRecipient(channelId, userId), {
418
+ body
419
+ });
887
420
  },
888
- async createChannel (guildId, options) {
889
- return await rest.post(rest.routes.guilds.channels(guildId), options);
421
+ async createAutomodRule (guildId, body, reason) {
422
+ return await rest.post(rest.routes.guilds.automod.rules(guildId), {
423
+ body,
424
+ reason
425
+ });
890
426
  },
891
- async createEmoji (guildId, options) {
892
- return await rest.post(rest.routes.guilds.emojis(guildId), options);
427
+ async createChannel (guildId, body, reason) {
428
+ return await rest.post(rest.routes.guilds.channels(guildId), {
429
+ body,
430
+ reason
431
+ });
893
432
  },
894
- async createGlobalApplicationCommand (command) {
895
- return await rest.post(rest.routes.interactions.commands.commands(rest.applicationId), command);
433
+ async createEmoji (guildId, body, reason) {
434
+ return await rest.post(rest.routes.guilds.emojis(guildId), {
435
+ body,
436
+ reason
437
+ });
438
+ },
439
+ async createGlobalApplicationCommand (body, options) {
440
+ const restOptions = {
441
+ body
442
+ };
443
+ if (options?.bearerToken) {
444
+ restOptions.unauthorized = true;
445
+ restOptions.headers = {
446
+ authorization: `Bearer ${options.bearerToken}`
447
+ };
448
+ }
449
+ return await rest.post(rest.routes.interactions.commands.commands(rest.applicationId), restOptions);
896
450
  },
897
- async createGuild (options) {
898
- return await rest.post(rest.routes.guilds.all(), options);
451
+ async createGuild (body) {
452
+ return await rest.post(rest.routes.guilds.all(), {
453
+ body
454
+ });
899
455
  },
900
- async createGuildApplicationCommand (command, guildId) {
901
- return await rest.post(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), command);
456
+ async createGuildApplicationCommand (body, guildId, options) {
457
+ const restOptions = {
458
+ body
459
+ };
460
+ if (options?.bearerToken) {
461
+ restOptions.unauthorized = true;
462
+ restOptions.headers = {
463
+ authorization: `Bearer ${options.bearerToken}`
464
+ };
465
+ }
466
+ return await rest.post(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), restOptions);
902
467
  },
903
- async createGuildFromTemplate (templateCode, options) {
904
- if (options.icon) {
905
- options.icon = await urlToBase64(options.icon);
468
+ async createGuildFromTemplate (templateCode, body) {
469
+ if (body.icon) {
470
+ body.icon = await urlToBase64(body.icon);
906
471
  }
907
- return await rest.post(rest.routes.guilds.templates.code(templateCode), options);
472
+ return await rest.post(rest.routes.guilds.templates.code(templateCode), {
473
+ body
474
+ });
908
475
  },
909
- async createGuildSticker (guildId, options) {
910
- return await rest.post(rest.routes.guilds.stickers(guildId), options);
476
+ async createGuildSticker (guildId, options, reason) {
477
+ const form = new FormData();
478
+ form.append('file', options.file.blob, options.file.name);
479
+ form.append('name', options.name);
480
+ form.append('description', options.description);
481
+ form.append('tags', options.tags);
482
+ return await rest.post(rest.routes.guilds.stickers(guildId), {
483
+ body: form,
484
+ reason
485
+ });
911
486
  },
912
- async createGuildTemplate (guildId, options) {
913
- return await rest.post(rest.routes.guilds.templates.all(guildId), options);
487
+ async createGuildTemplate (guildId, body) {
488
+ return await rest.post(rest.routes.guilds.templates.all(guildId), {
489
+ body
490
+ });
914
491
  },
915
- async createForumThread (channelId, options) {
916
- return await rest.post(rest.routes.channels.forum(channelId), options);
492
+ async createForumThread (channelId, body, reason) {
493
+ return await rest.post(rest.routes.channels.forum(channelId), {
494
+ body,
495
+ files: body.files,
496
+ reason
497
+ });
917
498
  },
918
- async createInvite (channelId, options = {}) {
919
- return await rest.post(rest.routes.channels.invites(channelId), options);
499
+ async createInvite (channelId, body = {}, reason) {
500
+ return await rest.post(rest.routes.channels.invites(channelId), {
501
+ body,
502
+ reason
503
+ });
920
504
  },
921
- async createRole (guildId, options, reason) {
505
+ async createRole (guildId, body, reason) {
922
506
  return await rest.post(rest.routes.guilds.roles.all(guildId), {
923
- ...options,
507
+ body,
924
508
  reason
925
509
  });
926
510
  },
927
- async createScheduledEvent (guildId, options) {
928
- return await rest.post(rest.routes.guilds.events.events(guildId), options);
511
+ async createScheduledEvent (guildId, body, reason) {
512
+ return await rest.post(rest.routes.guilds.events.events(guildId), {
513
+ body,
514
+ reason
515
+ });
929
516
  },
930
- async createStageInstance (options) {
931
- return await rest.post(rest.routes.channels.stages(), options);
517
+ async createStageInstance (body, reason) {
518
+ return await rest.post(rest.routes.channels.stages(), {
519
+ body,
520
+ reason
521
+ });
932
522
  },
933
- async createWebhook (channelId, options) {
523
+ async createWebhook (channelId, options, reason) {
934
524
  return await rest.post(rest.routes.channels.webhooks(channelId), {
935
- name: options.name,
936
- avatar: options.avatar ? await urlToBase64(options.avatar) : undefined,
937
- reason: options.reason
525
+ body: {
526
+ name: options.name,
527
+ avatar: options.avatar ? await urlToBase64(options.avatar) : undefined
528
+ },
529
+ reason
938
530
  });
939
531
  },
940
532
  async deleteAutomodRule (guildId, ruleId, reason) {
@@ -948,9 +540,9 @@ export function createRestManager(options) {
948
540
  });
949
541
  },
950
542
  async deleteChannelPermissionOverride (channelId, overwriteId, reason) {
951
- await rest.delete(rest.routes.channels.overwrite(channelId, overwriteId), reason ? {
543
+ await rest.delete(rest.routes.channels.overwrite(channelId, overwriteId), {
952
544
  reason
953
- } : undefined);
545
+ });
954
546
  },
955
547
  async deleteEmoji (guildId, id, reason) {
956
548
  await rest.delete(rest.routes.guilds.emoji(guildId, id), {
@@ -958,7 +550,9 @@ export function createRestManager(options) {
958
550
  });
959
551
  },
960
552
  async deleteFollowupMessage (token, messageId) {
961
- await rest.delete(rest.routes.interactions.responses.message(rest.applicationId, token, messageId));
553
+ await rest.delete(rest.routes.interactions.responses.message(rest.applicationId, token, messageId), {
554
+ unauthorized: true
555
+ });
962
556
  },
963
557
  async deleteGlobalApplicationCommand (commandId) {
964
558
  await rest.delete(rest.routes.interactions.commands.command(rest.applicationId, commandId));
@@ -970,20 +564,22 @@ export function createRestManager(options) {
970
564
  await rest.delete(rest.routes.interactions.commands.guilds.one(rest.applicationId, guildId, commandId));
971
565
  },
972
566
  async deleteGuildSticker (guildId, stickerId, reason) {
973
- await rest.delete(rest.routes.guilds.sticker(guildId, stickerId), reason ? {
567
+ await rest.delete(rest.routes.guilds.sticker(guildId, stickerId), {
974
568
  reason
975
- } : undefined);
569
+ });
976
570
  },
977
571
  async deleteGuildTemplate (guildId, templateCode) {
978
572
  await rest.delete(rest.routes.guilds.templates.guild(guildId, templateCode));
979
573
  },
980
- async deleteIntegration (guildId, integrationId) {
981
- await rest.delete(rest.routes.guilds.integration(guildId, integrationId));
574
+ async deleteIntegration (guildId, integrationId, reason) {
575
+ await rest.delete(rest.routes.guilds.integration(guildId, integrationId), {
576
+ reason
577
+ });
982
578
  },
983
579
  async deleteInvite (inviteCode, reason) {
984
- await rest.delete(rest.routes.guilds.invite(inviteCode), reason ? {
580
+ await rest.delete(rest.routes.guilds.invite(inviteCode), {
985
581
  reason
986
- } : undefined);
582
+ });
987
583
  },
988
584
  async deleteMessage (channelId, messageId, reason) {
989
585
  await rest.delete(rest.routes.channels.message(channelId, messageId), {
@@ -992,12 +588,16 @@ export function createRestManager(options) {
992
588
  },
993
589
  async deleteMessages (channelId, messageIds, reason) {
994
590
  await rest.post(rest.routes.channels.bulk(channelId), {
995
- messages: messageIds.slice(0, 100).map((id)=>id.toString()),
591
+ body: {
592
+ messages: messageIds.slice(0, 100).map((id)=>id.toString())
593
+ },
996
594
  reason
997
595
  });
998
596
  },
999
597
  async deleteOriginalInteractionResponse (token) {
1000
- await rest.delete(rest.routes.interactions.responses.original(rest.applicationId, token));
598
+ await rest.delete(rest.routes.interactions.responses.original(rest.applicationId, token), {
599
+ unauthorized: true
600
+ });
1001
601
  },
1002
602
  async deleteOwnReaction (channelId, messageId, reaction) {
1003
603
  reaction = processReactionString(reaction);
@@ -1010,16 +610,18 @@ export function createRestManager(options) {
1010
610
  reaction = processReactionString(reaction);
1011
611
  await rest.delete(rest.routes.channels.reactions.emoji(channelId, messageId, reaction));
1012
612
  },
1013
- async deleteRole (guildId, roleId) {
1014
- await rest.delete(rest.routes.guilds.roles.one(guildId, roleId));
613
+ async deleteRole (guildId, roleId, reason) {
614
+ await rest.delete(rest.routes.guilds.roles.one(guildId, roleId), {
615
+ reason
616
+ });
1015
617
  },
1016
618
  async deleteScheduledEvent (guildId, eventId) {
1017
619
  await rest.delete(rest.routes.guilds.events.event(guildId, eventId));
1018
620
  },
1019
621
  async deleteStageInstance (channelId, reason) {
1020
- await rest.delete(rest.routes.channels.stage(channelId), reason ? {
622
+ await rest.delete(rest.routes.channels.stage(channelId), {
1021
623
  reason
1022
- } : undefined);
624
+ });
1023
625
  },
1024
626
  async deleteUserReaction (channelId, messageId, userId, reaction) {
1025
627
  reaction = processReactionString(reaction);
@@ -1036,135 +638,255 @@ export function createRestManager(options) {
1036
638
  async deleteWebhookWithToken (webhookId, token) {
1037
639
  await rest.delete(rest.routes.webhooks.webhook(webhookId, token));
1038
640
  },
1039
- async editApplicationCommandPermissions (guildId, commandId, bearerToken, options) {
641
+ async editApplicationCommandPermissions (guildId, commandId, bearerToken, permissions) {
1040
642
  return await rest.put(rest.routes.interactions.commands.permission(rest.applicationId, guildId, commandId), {
1041
- permissions: options
1042
- }, {
643
+ body: {
644
+ permissions
645
+ },
1043
646
  headers: {
1044
647
  authorization: `Bearer ${bearerToken}`
1045
648
  }
1046
649
  });
1047
650
  },
1048
- async editAutomodRule (guildId, ruleId, options) {
1049
- return await rest.patch(rest.routes.guilds.automod.rule(guildId, ruleId), options);
651
+ async editAutomodRule (guildId, ruleId, body, reason) {
652
+ return await rest.patch(rest.routes.guilds.automod.rule(guildId, ruleId), {
653
+ body,
654
+ reason
655
+ });
1050
656
  },
1051
657
  async editBotProfile (options) {
1052
658
  const avatar = options?.botAvatarURL ? await urlToBase64(options?.botAvatarURL) : options?.botAvatarURL;
1053
- return await rest.patch(rest.routes.userBot(), {
1054
- username: options.username?.trim(),
1055
- avatar
659
+ return await rest.patch(rest.routes.currentUser(), {
660
+ body: {
661
+ username: options.username?.trim(),
662
+ avatar
663
+ }
1056
664
  });
1057
665
  },
1058
- async editChannel (channelId, options) {
1059
- return await rest.patch(rest.routes.channels.channel(channelId), options);
666
+ async editChannel (channelId, body, reason) {
667
+ return await rest.patch(rest.routes.channels.channel(channelId), {
668
+ body,
669
+ reason
670
+ });
1060
671
  },
1061
- async editChannelPermissionOverrides (channelId, options) {
1062
- await rest.put(rest.routes.channels.overwrite(channelId, options.id), options);
672
+ async editChannelPermissionOverrides (channelId, body, reason) {
673
+ await rest.put(rest.routes.channels.overwrite(channelId, body.id), {
674
+ body,
675
+ reason
676
+ });
1063
677
  },
1064
- async editChannelPositions (guildId, channelPositions) {
1065
- await rest.patch(rest.routes.guilds.channels(guildId), channelPositions);
678
+ async editChannelPositions (guildId, body) {
679
+ await rest.patch(rest.routes.guilds.channels(guildId), {
680
+ body
681
+ });
1066
682
  },
1067
- async editEmoji (guildId, id, options) {
1068
- return await rest.patch(rest.routes.guilds.emoji(guildId, id), options);
683
+ async editEmoji (guildId, id, body, reason) {
684
+ return await rest.patch(rest.routes.guilds.emoji(guildId, id), {
685
+ body,
686
+ reason
687
+ });
1069
688
  },
1070
- async editFollowupMessage (token, messageId, options) {
1071
- return await rest.patch(rest.routes.interactions.responses.message(rest.applicationId, token, messageId), options);
689
+ async editFollowupMessage (token, messageId, body) {
690
+ return await rest.patch(rest.routes.interactions.responses.message(rest.applicationId, token, messageId), {
691
+ body,
692
+ files: body.files,
693
+ unauthorized: true
694
+ });
1072
695
  },
1073
- async editGlobalApplicationCommand (commandId, options) {
1074
- return await rest.patch(rest.routes.interactions.commands.command(rest.applicationId, commandId), options);
696
+ async editGlobalApplicationCommand (commandId, body) {
697
+ return await rest.patch(rest.routes.interactions.commands.command(rest.applicationId, commandId), {
698
+ body
699
+ });
1075
700
  },
1076
- async editGuild (guildId, options) {
1077
- return await rest.patch(rest.routes.guilds.guild(guildId), options);
701
+ async editGuild (guildId, body, reason) {
702
+ return await rest.patch(rest.routes.guilds.guild(guildId), {
703
+ body,
704
+ reason
705
+ });
1078
706
  },
1079
- async editGuildApplicationCommand (commandId, guildId, options) {
1080
- return await rest.patch(rest.routes.interactions.commands.guilds.one(rest.applicationId, guildId, commandId), options);
707
+ async editGuildApplicationCommand (commandId, guildId, body) {
708
+ return await rest.patch(rest.routes.interactions.commands.guilds.one(rest.applicationId, guildId, commandId), {
709
+ body
710
+ });
1081
711
  },
1082
712
  async editGuildMfaLevel (guildId, mfaLevel, reason) {
1083
713
  await rest.post(rest.routes.guilds.mfa(guildId), {
1084
- level: mfaLevel,
714
+ body: {
715
+ level: mfaLevel
716
+ },
1085
717
  reason
1086
718
  });
1087
719
  },
1088
- async editGuildSticker (guildId, stickerId, options) {
1089
- return await rest.patch(rest.routes.guilds.sticker(guildId, stickerId), options);
720
+ async editGuildSticker (guildId, stickerId, body, reason) {
721
+ return await rest.patch(rest.routes.guilds.sticker(guildId, stickerId), {
722
+ body,
723
+ reason
724
+ });
1090
725
  },
1091
- async editGuildTemplate (guildId, templateCode, options) {
1092
- return await rest.patch(rest.routes.guilds.templates.guild(guildId, templateCode), options);
726
+ async editGuildTemplate (guildId, templateCode, body) {
727
+ return await rest.patch(rest.routes.guilds.templates.guild(guildId, templateCode), {
728
+ body
729
+ });
1093
730
  },
1094
- async editMessage (channelId, messageId, options) {
1095
- return await rest.patch(rest.routes.channels.message(channelId, messageId), options);
731
+ async editMessage (channelId, messageId, body) {
732
+ return await rest.patch(rest.routes.channels.message(channelId, messageId), {
733
+ body,
734
+ files: body.files
735
+ });
1096
736
  },
1097
- async editOriginalInteractionResponse (token, options) {
1098
- return await rest.patch(rest.routes.interactions.responses.original(rest.applicationId, token), options);
737
+ async editOriginalInteractionResponse (token, body) {
738
+ return await rest.patch(rest.routes.interactions.responses.original(rest.applicationId, token), {
739
+ body,
740
+ files: body.files
741
+ });
1099
742
  },
1100
743
  async editOriginalWebhookMessage (webhookId, token, options) {
1101
744
  return await rest.patch(rest.routes.webhooks.original(webhookId, token, options), {
1102
- type: InteractionResponseTypes.UpdateMessage,
1103
- data: options
745
+ body: {
746
+ type: InteractionResponseTypes.UpdateMessage,
747
+ data: options
748
+ },
749
+ files: options.files,
750
+ unauthorized: true
1104
751
  });
1105
752
  },
1106
753
  async editOwnVoiceState (guildId, options) {
1107
754
  await rest.patch(rest.routes.guilds.voice(guildId), {
1108
- channel_id: options.channelId,
1109
- suppress: options.suppress,
1110
- request_to_speak_timestamp: options.requestToSpeakTimestamp ? new Date(options.requestToSpeakTimestamp).toISOString() : options.requestToSpeakTimestamp
755
+ body: {
756
+ ...options,
757
+ request_to_speak_timestamp: options.requestToSpeakTimestamp ? new Date(options.requestToSpeakTimestamp).toISOString() : options.requestToSpeakTimestamp
758
+ }
1111
759
  });
1112
760
  },
1113
- async editScheduledEvent (guildId, eventId, options) {
1114
- return await rest.patch(rest.routes.guilds.events.event(guildId, eventId), options);
761
+ async editScheduledEvent (guildId, eventId, body, reason) {
762
+ return await rest.patch(rest.routes.guilds.events.event(guildId, eventId), {
763
+ body,
764
+ reason
765
+ });
1115
766
  },
1116
- async editRole (guildId, roleId, options) {
1117
- return await rest.patch(rest.routes.guilds.roles.one(guildId, roleId), options);
767
+ async editRole (guildId, roleId, body, reason) {
768
+ return await rest.patch(rest.routes.guilds.roles.one(guildId, roleId), {
769
+ body,
770
+ reason
771
+ });
1118
772
  },
1119
- async editRolePositions (guildId, options) {
1120
- return await rest.patch(rest.routes.guilds.roles.all(guildId), options);
773
+ async editRolePositions (guildId, body, reason) {
774
+ return await rest.patch(rest.routes.guilds.roles.all(guildId), {
775
+ body,
776
+ reason
777
+ });
1121
778
  },
1122
- async editStageInstance (channelId, data) {
779
+ async editStageInstance (channelId, topic, reason) {
1123
780
  return await rest.patch(rest.routes.channels.stage(channelId), {
1124
- topic: data.topic
781
+ body: {
782
+ topic
783
+ },
784
+ reason
1125
785
  });
1126
786
  },
1127
787
  async editUserVoiceState (guildId, options) {
1128
788
  await rest.patch(rest.routes.guilds.voice(guildId, options.userId), {
1129
- channel_id: options.channelId,
1130
- suppress: options.suppress,
1131
- user_id: options.userId
789
+ body: options
1132
790
  });
1133
791
  },
1134
- async editWebhook (webhookId, options) {
1135
- return await rest.patch(rest.routes.webhooks.id(webhookId), options);
792
+ async editWebhook (webhookId, body, reason) {
793
+ return await rest.patch(rest.routes.webhooks.id(webhookId), {
794
+ body,
795
+ reason
796
+ });
1136
797
  },
1137
798
  async editWebhookMessage (webhookId, token, messageId, options) {
1138
- return await rest.patch(rest.routes.webhooks.message(webhookId, token, messageId, options), options);
799
+ return await rest.patch(rest.routes.webhooks.message(webhookId, token, messageId, options), {
800
+ body: options,
801
+ files: options.files
802
+ });
1139
803
  },
1140
- async editWebhookWithToken (webhookId, token, options) {
1141
- return await rest.patch(rest.routes.webhooks.webhook(webhookId, token), options);
804
+ async editWebhookWithToken (webhookId, token, body) {
805
+ return await rest.patch(rest.routes.webhooks.webhook(webhookId, token), {
806
+ body
807
+ });
1142
808
  },
1143
- async editWelcomeScreen (guildId, options) {
1144
- return await rest.patch(rest.routes.guilds.welcome(guildId), options);
809
+ async editWelcomeScreen (guildId, body, reason) {
810
+ return await rest.patch(rest.routes.guilds.welcome(guildId), {
811
+ body,
812
+ reason
813
+ });
1145
814
  },
1146
- async editWidgetSettings (guildId, options) {
1147
- return await rest.patch(rest.routes.guilds.widget(guildId), options);
815
+ async editWidgetSettings (guildId, body, reason) {
816
+ return await rest.patch(rest.routes.guilds.widget(guildId), {
817
+ body,
818
+ reason
819
+ });
1148
820
  },
1149
821
  async executeWebhook (webhookId, token, options) {
1150
- return await rest.post(rest.routes.webhooks.webhook(webhookId, token, options), options);
822
+ return await rest.post(rest.routes.webhooks.webhook(webhookId, token, options), {
823
+ body: options
824
+ });
1151
825
  },
1152
826
  async followAnnouncement (sourceChannelId, targetChannelId) {
1153
827
  return await rest.post(rest.routes.channels.follow(sourceChannelId), {
1154
- webhook_channel_id: targetChannelId
828
+ body: {
829
+ webhook_channel_id: targetChannelId
830
+ }
1155
831
  });
1156
832
  },
1157
833
  async getActiveThreads (guildId) {
1158
834
  return await rest.get(rest.routes.channels.threads.active(guildId));
1159
835
  },
1160
- async getApplicationCommandPermission (guildId, commandId) {
1161
- return await rest.get(rest.routes.interactions.commands.permission(rest.applicationId, guildId, commandId));
1162
- },
1163
- async getApplicationCommandPermissions (guildId) {
1164
- return await rest.get(rest.routes.interactions.commands.permissions(rest.applicationId, guildId));
836
+ async getApplicationCommandPermission (guildId, commandId, options) {
837
+ const restOptions = {};
838
+ if (options?.accessToken) {
839
+ restOptions.unauthorized = true;
840
+ restOptions.headers = {
841
+ authorization: `Bearer ${options.accessToken}`
842
+ };
843
+ }
844
+ return await rest.get(rest.routes.interactions.commands.permission(options?.applicationId ?? rest.applicationId, guildId, commandId), restOptions);
845
+ },
846
+ async getApplicationCommandPermissions (guildId, options) {
847
+ const restOptions = {};
848
+ if (options?.accessToken) {
849
+ restOptions.unauthorized = true;
850
+ restOptions.headers = {
851
+ authorization: `Bearer ${options.accessToken}`
852
+ };
853
+ }
854
+ return await rest.get(rest.routes.interactions.commands.permissions(options?.applicationId ?? rest.applicationId, guildId), restOptions);
1165
855
  },
1166
856
  async getApplicationInfo () {
1167
- return await rest.get(rest.routes.oauth2Application());
857
+ return await rest.get(rest.routes.oauth2.application());
858
+ },
859
+ async getCurrentAuthenticationInfo (token) {
860
+ return await rest.get(rest.routes.oauth2.currentAuthorization(), {
861
+ headers: {
862
+ authorization: `Bearer ${token}`
863
+ },
864
+ unauthorized: true
865
+ });
866
+ },
867
+ async exchangeToken (body) {
868
+ const restOptions = {
869
+ body,
870
+ headers: {
871
+ 'content-type': 'application/x-www-form-urlencoded'
872
+ },
873
+ unauthorized: true
874
+ };
875
+ if (body.grantType === 'client_credentials') {
876
+ const basicCredentials = Buffer.from(`${body.clientId}:${body.clientSecret}`);
877
+ restOptions.headers.authorization = `Basic ${basicCredentials.toString('base64')}`;
878
+ restOptions.body.scope = body.scope.join(' ');
879
+ }
880
+ return await rest.post(rest.routes.oauth2.tokenExchange(), restOptions);
881
+ },
882
+ async revokeToken (body) {
883
+ await rest.post(rest.routes.oauth2.tokenRevoke(), {
884
+ body,
885
+ headers: {
886
+ 'content-type': 'application/x-www-form-urlencoded'
887
+ },
888
+ unauthorized: true
889
+ });
1168
890
  },
1169
891
  async getAuditLog (guildId, options) {
1170
892
  return await rest.get(rest.routes.guilds.auditlogs(guildId, options));
@@ -1198,7 +920,14 @@ export function createRestManager(options) {
1198
920
  },
1199
921
  async getDmChannel (userId) {
1200
922
  return await rest.post(rest.routes.channels.dm(), {
1201
- recipient_id: userId.toString()
923
+ body: {
924
+ recipient_id: userId
925
+ }
926
+ });
927
+ },
928
+ async getGroupDmChannel (body) {
929
+ return await rest.post(rest.routes.channels.dm(), {
930
+ body
1202
931
  });
1203
932
  },
1204
933
  async getEmoji (guildId, emojiId) {
@@ -1208,7 +937,9 @@ export function createRestManager(options) {
1208
937
  return await rest.get(rest.routes.guilds.emojis(guildId));
1209
938
  },
1210
939
  async getFollowupMessage (token, messageId) {
1211
- return await rest.get(rest.routes.interactions.responses.message(rest.applicationId, token, messageId));
940
+ return await rest.get(rest.routes.interactions.responses.message(rest.applicationId, token, messageId), {
941
+ unauthorized: true
942
+ });
1212
943
  },
1213
944
  async getGatewayBot () {
1214
945
  return await rest.get(rest.routes.gatewayBot());
@@ -1224,6 +955,14 @@ export function createRestManager(options) {
1224
955
  }) {
1225
956
  return await rest.get(rest.routes.guilds.guild(guildId, options.counts));
1226
957
  },
958
+ async getGuilds (token, options) {
959
+ return await rest.get(rest.routes.guilds.userGuilds(options), {
960
+ headers: {
961
+ authorization: `Bearer ${token}`
962
+ },
963
+ unauthorized: true
964
+ });
965
+ },
1227
966
  async getGuildApplicationCommand (commandId, guildId) {
1228
967
  return await rest.get(rest.routes.interactions.commands.guilds.one(rest.applicationId, guildId, commandId));
1229
968
  },
@@ -1261,7 +1000,9 @@ export function createRestManager(options) {
1261
1000
  return await rest.get(rest.routes.nitroStickerPacks());
1262
1001
  },
1263
1002
  async getOriginalInteractionResponse (token) {
1264
- return await rest.get(rest.routes.interactions.responses.original(rest.applicationId, token));
1003
+ return await rest.get(rest.routes.interactions.responses.original(rest.applicationId, token), {
1004
+ unauthorized: true
1005
+ });
1265
1006
  },
1266
1007
  async getPinnedMessages (channelId) {
1267
1008
  return await rest.get(rest.routes.channels.pins(channelId));
@@ -1317,6 +1058,30 @@ export function createRestManager(options) {
1317
1058
  async getUser (id) {
1318
1059
  return await rest.get(rest.routes.user(id));
1319
1060
  },
1061
+ async getCurrentUser (token) {
1062
+ return await rest.get(rest.routes.currentUser(), {
1063
+ headers: {
1064
+ authorization: `Bearer ${token}`
1065
+ },
1066
+ unauthorized: true
1067
+ });
1068
+ },
1069
+ async getUserConnections (token) {
1070
+ return await rest.get(rest.routes.oauth2.connections(), {
1071
+ headers: {
1072
+ authorization: `Bearer ${token}`
1073
+ },
1074
+ unauthorized: true
1075
+ });
1076
+ },
1077
+ async getUserApplicationRoleConnection (token, applicationId) {
1078
+ return await rest.get(rest.routes.oauth2.roleConnections(applicationId), {
1079
+ headers: {
1080
+ authorization: `Bearer ${token}`
1081
+ },
1082
+ unauthorized: true
1083
+ });
1084
+ },
1320
1085
  async getVanityUrl (guildId) {
1321
1086
  return await rest.get(rest.routes.guilds.vanity(guildId));
1322
1087
  },
@@ -1361,66 +1126,74 @@ export function createRestManager(options) {
1361
1126
  async removeThreadMember (channelId, userId) {
1362
1127
  await rest.delete(rest.routes.channels.threads.user(channelId, userId));
1363
1128
  },
1129
+ async removeDmRecipient (channelId, userId) {
1130
+ await rest.delete(rest.routes.channels.dmRecipient(channelId, userId));
1131
+ },
1364
1132
  async sendFollowupMessage (token, options) {
1365
- return await new Promise((resolve, reject)=>{
1366
- rest.sendRequest({
1367
- url: rest.routes.webhooks.webhook(rest.applicationId, token),
1368
- method: 'POST',
1369
- body: options,
1370
- retryCount: 0,
1371
- retryRequest: async function(options) {
1372
- // TODO: should change to reprocess queue item
1373
- await rest.sendRequest(options);
1374
- },
1375
- resolve: (data)=>{
1376
- resolve(data.status !== 204 ? JSON.parse(data.body ?? '{}') : undefined);
1377
- },
1378
- reject
1379
- });
1133
+ return await rest.post(rest.routes.webhooks.webhook(rest.applicationId, token), {
1134
+ body: options,
1135
+ files: options.files,
1136
+ unauthorized: true
1380
1137
  });
1381
1138
  },
1382
1139
  async sendInteractionResponse (interactionId, token, options) {
1383
- await new Promise((resolve, reject)=>{
1384
- rest.sendRequest({
1385
- url: rest.routes.interactions.responses.callback(interactionId, token),
1386
- method: 'POST',
1387
- body: options,
1388
- retryCount: 0,
1389
- retryRequest: async function(options) {
1390
- // TODO: should change to reprocess queue item
1391
- await rest.sendRequest(options);
1392
- },
1393
- resolve: (data)=>{
1394
- resolve(data.status !== 204 ? JSON.parse(data.body ?? '{}') : undefined);
1395
- },
1396
- reject
1397
- });
1140
+ return await rest.post(rest.routes.interactions.responses.callback(interactionId, token), {
1141
+ body: options,
1142
+ files: options.data?.files,
1143
+ runThroughQueue: false,
1144
+ unauthorized: true
1398
1145
  });
1399
1146
  },
1400
- async sendMessage (channelId, options) {
1401
- return await rest.post(rest.routes.channels.messages(channelId), options);
1147
+ async sendMessage (channelId, body) {
1148
+ return await rest.post(rest.routes.channels.messages(channelId), {
1149
+ body,
1150
+ files: body.files
1151
+ });
1402
1152
  },
1403
- async startThreadWithMessage (channelId, messageId, options) {
1404
- return await rest.post(rest.routes.channels.threads.message(channelId, messageId), options);
1153
+ async startThreadWithMessage (channelId, messageId, body, reason) {
1154
+ return await rest.post(rest.routes.channels.threads.message(channelId, messageId), {
1155
+ body,
1156
+ reason
1157
+ });
1405
1158
  },
1406
- async startThreadWithoutMessage (channelId, options) {
1407
- return await rest.post(rest.routes.channels.threads.all(channelId), options);
1159
+ async startThreadWithoutMessage (channelId, body, reason) {
1160
+ return await rest.post(rest.routes.channels.threads.all(channelId), {
1161
+ body,
1162
+ reason
1163
+ });
1408
1164
  },
1409
1165
  async syncGuildTemplate (guildId) {
1410
1166
  return await rest.put(rest.routes.guilds.templates.all(guildId));
1411
1167
  },
1412
- async banMember (guildId, userId, options) {
1413
- await rest.put(rest.routes.guilds.members.ban(guildId, userId), options);
1168
+ async banMember (guildId, userId, body, reason) {
1169
+ await rest.put(rest.routes.guilds.members.ban(guildId, userId), {
1170
+ body,
1171
+ reason
1172
+ });
1414
1173
  },
1415
- async editBotMember (guildId, options) {
1416
- return await rest.patch(rest.routes.guilds.members.bot(guildId), options);
1174
+ async editBotMember (guildId, body, reason) {
1175
+ return await rest.patch(rest.routes.guilds.members.bot(guildId), {
1176
+ body,
1177
+ reason
1178
+ });
1417
1179
  },
1418
- async editMember (guildId, userId, options) {
1419
- return await rest.patch(rest.routes.guilds.members.member(guildId, userId), options);
1180
+ async editMember (guildId, userId, body, reason) {
1181
+ return await rest.patch(rest.routes.guilds.members.member(guildId, userId), {
1182
+ body,
1183
+ reason
1184
+ });
1420
1185
  },
1421
1186
  async getMember (guildId, userId) {
1422
1187
  return await rest.get(rest.routes.guilds.members.member(guildId, userId));
1423
1188
  },
1189
+ async getCurrentMember (guildId, token) {
1190
+ return await rest.get(rest.routes.guilds.members.currentMember(guildId), {
1191
+ headers: {
1192
+ authorization: `Bearer ${token}`
1193
+ },
1194
+ unauthorized: true
1195
+ });
1196
+ },
1424
1197
  async getMembers (guildId, options) {
1425
1198
  return await rest.get(rest.routes.guilds.members.members(guildId, options));
1426
1199
  },
@@ -1430,35 +1203,98 @@ export function createRestManager(options) {
1430
1203
  });
1431
1204
  },
1432
1205
  async pinMessage (channelId, messageId, reason) {
1433
- await rest.put(rest.routes.channels.pin(channelId, messageId), reason ? {
1206
+ await rest.put(rest.routes.channels.pin(channelId, messageId), {
1434
1207
  reason
1435
- } : undefined);
1208
+ });
1436
1209
  },
1437
- async pruneMembers (guildId, options) {
1438
- return await rest.post(rest.routes.guilds.members.prune(guildId), options);
1210
+ async pruneMembers (guildId, body, reason) {
1211
+ return await rest.post(rest.routes.guilds.members.prune(guildId), {
1212
+ body,
1213
+ reason
1214
+ });
1439
1215
  },
1440
1216
  async searchMembers (guildId, query, options) {
1441
1217
  return await rest.get(rest.routes.guilds.members.search(guildId, query, options));
1442
1218
  },
1443
- async unbanMember (guildId, userId) {
1444
- await rest.delete(rest.routes.guilds.members.ban(guildId, userId));
1219
+ async unbanMember (guildId, userId, reason) {
1220
+ await rest.delete(rest.routes.guilds.members.ban(guildId, userId), {
1221
+ reason
1222
+ });
1445
1223
  },
1446
1224
  async unpinMessage (channelId, messageId, reason) {
1447
- await rest.delete(rest.routes.channels.pin(channelId, messageId), reason ? {
1225
+ await rest.delete(rest.routes.channels.pin(channelId, messageId), {
1448
1226
  reason
1449
- } : undefined);
1227
+ });
1450
1228
  },
1451
1229
  async triggerTypingIndicator (channelId) {
1452
1230
  await rest.post(rest.routes.channels.typing(channelId));
1453
1231
  },
1454
- async upsertGlobalApplicationCommands (commands) {
1455
- return await rest.put(rest.routes.interactions.commands.commands(rest.applicationId), commands);
1232
+ async upsertGlobalApplicationCommands (body, options) {
1233
+ const restOptions = {
1234
+ body
1235
+ };
1236
+ if (options?.bearerToken) {
1237
+ restOptions.unauthorized = true;
1238
+ restOptions.headers = {
1239
+ authorization: `Bearer ${options.bearerToken}`
1240
+ };
1241
+ }
1242
+ return await rest.put(rest.routes.interactions.commands.commands(rest.applicationId), restOptions);
1243
+ },
1244
+ async upsertGuildApplicationCommands (guildId, body, options) {
1245
+ const restOptions = {
1246
+ body
1247
+ };
1248
+ if (options?.bearerToken) {
1249
+ restOptions.unauthorized = true;
1250
+ restOptions.headers = {
1251
+ authorization: `Bearer ${options.bearerToken}`
1252
+ };
1253
+ }
1254
+ return await rest.put(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), restOptions);
1255
+ },
1256
+ async editUserApplicationRoleConnection (token, applicationId, body) {
1257
+ return await rest.put(rest.routes.oauth2.roleConnections(applicationId), {
1258
+ body,
1259
+ headers: {
1260
+ authorization: `Bearer ${token}`
1261
+ },
1262
+ unauthorized: true
1263
+ });
1264
+ },
1265
+ async addGuildMember (guildId, userId, body) {
1266
+ return await rest.put(rest.routes.guilds.members.member(guildId, userId), {
1267
+ body
1268
+ });
1456
1269
  },
1457
- async upsertGuildApplicationCommands (guildId, commands) {
1458
- return await rest.put(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), commands);
1270
+ preferSnakeCase (enabled) {
1271
+ const camelizer = enabled ? (x)=>x : camelize;
1272
+ rest.get = async (url, options)=>{
1273
+ return camelizer(await rest.makeRequest('GET', url, options));
1274
+ };
1275
+ rest.post = async (url, options)=>{
1276
+ return camelizer(await rest.makeRequest('POST', url, options));
1277
+ };
1278
+ rest.delete = async (url, options)=>{
1279
+ camelizer(await rest.makeRequest('DELETE', url, options));
1280
+ };
1281
+ rest.patch = async (url, options)=>{
1282
+ return camelizer(await rest.makeRequest('PATCH', url, options));
1283
+ };
1284
+ rest.put = async (url, options)=>{
1285
+ return camelizer(await rest.makeRequest('PUT', url, options));
1286
+ };
1287
+ return rest;
1459
1288
  }
1460
1289
  };
1461
1290
  return rest;
1462
1291
  }
1292
+ var HttpResponseCode;
1293
+ (function(HttpResponseCode) {
1294
+ HttpResponseCode[HttpResponseCode[/** Minimum value of a code in oder to consider that it was successful. */ "Success"] = 200] = "Success";
1295
+ HttpResponseCode[HttpResponseCode[/** Request completed successfully, but Discord returned an empty body. */ "NoContent"] = 204] = "NoContent";
1296
+ HttpResponseCode[HttpResponseCode[/** Minimum value of a code in order to consider that something went wrong. */ "Error"] = 400] = "Error";
1297
+ HttpResponseCode[HttpResponseCode[/** This request got rate limited. */ "TooManyRequests"] = 429] = "TooManyRequests";
1298
+ })(HttpResponseCode || (HttpResponseCode = {}));
1463
1299
 
1464
1300
  //# sourceMappingURL=manager.js.map