@discordeno/rest 19.0.0-next.8bb91fa → 19.0.0-next.8d1ba2a

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,508 +1,40 @@
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 { calculateBits, camelToSnakeCase, camelize, delay, getBotIdFromToken, logger, processReactionString, urlToBase64 } from '@discordeno/utils';
4
2
  import { createInvalidRequestBucket } from './invalidBucket.js';
5
3
  import { Queue } from './queue.js';
4
+ import { InteractionResponseTypes } from '@discordeno/types';
5
+ import { createRoutes } from './routes.js';
6
6
  // TODO: make dynamic based on package.json file
7
7
  const version = '19.0.0-alpha.1';
8
+ export const DISCORD_API_VERSION = 10;
9
+ export const DISCORD_API_URL = 'https://discord.com/api';
10
+ export const AUDIT_LOG_REASON_HEADER = 'x-audit-log-reason';
11
+ export const RATE_LIMIT_REMAINING_HEADER = 'x-ratelimit-remaining';
12
+ export const RATE_LIMIT_RESET_AFTER_HEADER = 'x-ratelimit-reset-after';
13
+ export const RATE_LIMIT_GLOBAL_HEADER = 'x-ratelimit-global';
14
+ export const RATE_LIMIT_BUCKET_HEADER = 'x-ratelimit-bucket';
15
+ export const RATE_LIMIT_LIMIT_HEADER = 'x-ratelimit-limit';
16
+ export const RATE_LIMIT_SCOPE_HEADER = 'x-ratelimit-scope';
8
17
  export function createRestManager(options) {
9
- // Falsy token string check
10
- if (!options.token) throw new Error('You must provide a valid token.');
18
+ const applicationId = options.applicationId ? BigInt(options.applicationId) : options.token ? getBotIdFromToken(options.token) : undefined;
19
+ if (!applicationId) {
20
+ 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.');
21
+ }
22
+ const baseUrl = options.proxy?.baseUrl ?? DISCORD_API_URL;
11
23
  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,
24
+ applicationId,
25
+ authorization: options.proxy?.authorization,
26
+ baseUrl,
27
+ deleteQueueDelay: 60000,
17
28
  globallyRateLimited: false,
29
+ invalidBucket: createInvalidRequestBucket({}),
30
+ isProxied: !baseUrl.startsWith(DISCORD_API_URL),
31
+ maxRetryCount: Infinity,
18
32
  processingRateLimitedPaths: false,
19
- deleteQueueDelay: 60000,
20
33
  queues: new Map(),
21
34
  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
- }
505
- },
35
+ token: options.token,
36
+ version: options.version ?? DISCORD_API_VERSION,
37
+ routes: createRoutes(),
506
38
  checkRateLimits (url) {
507
39
  const ratelimited = rest.rateLimitedPaths.get(url);
508
40
  const global = rest.rateLimitedPaths.get('global');
@@ -523,76 +55,74 @@ export function createRestManager(options) {
523
55
  }
524
56
  const newObj = {};
525
57
  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;
58
+ const value = obj[key];
59
+ // Some falsy values should be allowed like null or 0
60
+ if (value !== undefined) {
61
+ switch(key){
62
+ case 'permissions':
63
+ case 'allow':
64
+ case 'deny':
65
+ newObj[key] = calculateBits(value);
66
+ continue;
67
+ case 'defaultMemberPermissions':
68
+ newObj.default_member_permissions = calculateBits(value);
69
+ continue;
70
+ case 'nameLocalizations':
71
+ newObj.name_localizations = value;
72
+ continue;
73
+ case 'descriptionLocalizations':
74
+ newObj.description_localizations = value;
75
+ continue;
76
+ }
538
77
  }
539
- newObj[camelToSnakeCase(key)] = rest.changeToDiscordFormat(obj[key]);
78
+ newObj[camelToSnakeCase(key)] = rest.changeToDiscordFormat(value);
540
79
  }
541
80
  return newObj;
542
81
  }
543
82
  if (typeof obj === 'bigint') return obj.toString();
544
83
  return obj;
545
84
  },
546
- createRequest (options) {
85
+ createRequestBody (method, options) {
547
86
  const headers = {
548
87
  'user-agent': `DiscordBot (https://github.com/discordeno/discordeno, v${version})`
549
88
  };
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
- }
89
+ if (options?.unauthorized !== false) headers.authorization = `Bot ${rest.token}`;
561
90
  // 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;
91
+ if (options?.reason !== undefined) {
92
+ headers[AUDIT_LOG_REASON_HEADER] = encodeURIComponent(options?.reason);
565
93
  }
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';
94
+ let body;
95
+ // TODO: check if we need to add specific check for GET method
96
+ // Since GET does not allow bodies
97
+ // Have to check for attachments first, since body then has to be send in a different way.
98
+ if (options?.files !== undefined) {
99
+ const form = new FormData();
100
+ for(let i = 0; i < options.files.length; ++i){
101
+ form.append(`file${i}`, options.files[i].blob, options.files[i].name);
102
+ }
103
+ form.append('payload_json', JSON.stringify({
104
+ ...options.body,
105
+ files: undefined
106
+ }));
107
+ body = form;
108
+ // No need to set the `content-type` header since `fetch` does that automatically for us when we use a `FormData` object.
109
+ } else if (options?.body !== undefined) {
110
+ if (options.body instanceof FormData) {
111
+ body = options.body;
112
+ // No need to set the `content-type` header since `fetch` does that automatically for us when we use a `FormData` object.
113
+ } else {
114
+ body = JSON.stringify(rest.changeToDiscordFormat(options.body));
115
+ headers['content-type'] = `application/json`;
590
116
  }
591
117
  }
118
+ // SOMETIMES SPECIAL HEADERS (E.G. CUSTOM AUTHORIZATION) NEED TO BE USED
119
+ if (options?.headers) {
120
+ Object.assign(headers, options.headers);
121
+ }
592
122
  return {
123
+ body,
593
124
  headers,
594
- body: options.body?.file ?? JSON.stringify(rest.changeToDiscordFormat(options.body)),
595
- method: options.method
125
+ method
596
126
  };
597
127
  },
598
128
  processRateLimitedPaths () {
@@ -625,13 +155,13 @@ export function createRestManager(options) {
625
155
  /** Processes the rate limit headers and determines if it needs to be rate limited and returns the bucket id if available */ processHeaders (url, headers) {
626
156
  let rateLimited = false;
627
157
  // GET ALL NECESSARY HEADERS
628
- const remaining = headers.get('x-ratelimit-remaining');
629
- const retryAfter = headers.get('x-ratelimit-reset-after');
158
+ const remaining = headers.get(RATE_LIMIT_REMAINING_HEADER);
159
+ const retryAfter = headers.get(RATE_LIMIT_RESET_AFTER_HEADER);
630
160
  const reset = Date.now() + Number(retryAfter) * 1000;
631
- const global = headers.get('x-ratelimit-global');
161
+ const global = headers.get(RATE_LIMIT_GLOBAL_HEADER);
632
162
  // undefined override null needed for typings
633
- const bucketId = headers.get('x-ratelimit-bucket') ?? undefined;
634
- const limit = headers.get('x-ratelimit-limit');
163
+ const bucketId = headers.get(RATE_LIMIT_BUCKET_HEADER) ?? undefined;
164
+ const limit = headers.get(RATE_LIMIT_LIMIT_HEADER);
635
165
  rest.queues.get(url)?.handleCompletedRequest({
636
166
  remaining: remaining ? Number(remaining) : undefined,
637
167
  interval: retryAfter ? Number(retryAfter) * 1000 : undefined,
@@ -686,13 +216,8 @@ export function createRestManager(options) {
686
216
  return rateLimited ? bucketId : undefined;
687
217
  },
688
218
  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
- });
219
+ const url = `${rest.baseUrl}/v${rest.version}${options.route}`;
220
+ const payload = rest.createRequestBody(options.method, options.requestBodyOptions);
696
221
  logger.debug(`sending request to ${url}`, 'with payload:', {
697
222
  ...payload,
698
223
  headers: {
@@ -700,80 +225,86 @@ export function createRestManager(options) {
700
225
  authorization: 'Bot tokenhere'
701
226
  }
702
227
  });
703
- const response = await fetch(url, payload);
228
+ const response = await fetch(url, payload).catch(async (error)=>{
229
+ logger.error(error);
230
+ // Mark request and completed
231
+ rest.invalidBucket.handleCompletedRequest(999, false);
232
+ options.reject({
233
+ ok: false,
234
+ status: 999,
235
+ error: 'Possible network or request shape issue occurred. If this is rare, its a network glitch. If it occurs a lot something is wrong.'
236
+ });
237
+ throw error;
238
+ });
704
239
  logger.debug(`request fetched from ${url} with status ${response.status} & ${response.statusText}`);
240
+ // Mark request and completed
241
+ rest.invalidBucket.handleCompletedRequest(response.status, response.headers.get(RATE_LIMIT_SCOPE_HEADER) === 'shared');
705
242
  // Set the bucket id if it was available on the headers
706
- const bucketId = rest.processHeaders(rest.simplifyUrl(options.url, options.method), response.headers);
243
+ const bucketId = rest.processHeaders(rest.simplifyUrl(options.route, options.method), response.headers);
707
244
  if (bucketId) options.bucketId = bucketId;
708
245
  if (response.status < 200 || response.status >= 400) {
709
246
  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);
247
+ if (response.status !== 429) {
248
+ options.reject({
249
+ ok: false,
250
+ status: response.status,
251
+ body: await response.text()
252
+ });
253
+ return;
731
254
  }
732
- options.reject({
733
- ok: false,
734
- status: response.status,
735
- body: JSON.stringify(await response.json())
736
- });
737
- return;
255
+ logger.debug(`Request to ${url} was ratelimited.`);
256
+ // Too many attempts, get rid of request from queue.
257
+ if (options.retryCount >= rest.maxRetryCount) {
258
+ logger.debug(`Request to ${url} exceeded the maximum allowed retries.`, 'with payload:', payload);
259
+ // rest.debug(`[REST - RetriesMaxed] ${JSON.stringify(options)}`)
260
+ options.reject({
261
+ ok: false,
262
+ status: response.status,
263
+ error: 'The request was rate limited and it maxed out the retries limit.'
264
+ });
265
+ return;
266
+ }
267
+ options.retryCount += 1;
268
+ const resetAfter = response.headers.get(RATE_LIMIT_RESET_AFTER_HEADER);
269
+ if (resetAfter) await delay(Number(resetAfter) * 1000);
270
+ // process the response to prevent mem leak
271
+ await response.arrayBuffer();
272
+ return await options.retryRequest?.(options);
738
273
  }
739
- const is204 = response.status === 204;
740
- const json = is204 ? undefined : await response.json();
741
- // Discord sometimes sends no response with 204 code
274
+ // Discord sometimes sends no response with no content.
742
275
  options.resolve({
743
276
  ok: true,
744
277
  status: response.status,
745
- body: JSON.stringify(json)
278
+ body: response.status === 204 ? undefined : await response.text()
746
279
  });
747
280
  },
748
- // Credits: github.com/abalabahaha/eris lib/rest/RequestHandler.js#L397
749
- // Modified for our use-case
750
281
  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);
282
+ const parts = url.split('/');
283
+ const secondLastPart = parts[parts.length - 2];
284
+ if (secondLastPart === 'channels' || secondLastPart === 'guilds') {
285
+ return url;
286
+ }
287
+ if (secondLastPart === 'reactions' || parts[parts.length - 1] === '@me') {
288
+ parts.splice(-2);
289
+ parts.push('reactions');
290
+ } else {
291
+ parts.splice(-1);
292
+ parts.push('x');
760
293
  }
761
- // Delete Message endpoint has its own rate limit
762
- if (method === 'DELETE' && route.endsWith('/messages/x')) {
763
- route = method + route;
294
+ if (parts[parts.length - 3] === 'reactions') {
295
+ parts.splice(-2);
296
+ }
297
+ if (method === 'DELETE' && secondLastPart === 'messages') {
298
+ return `D${parts.join('/')}`;
299
+ }
300
+ return parts.join('/');
301
+ },
302
+ async processRequest (request) {
303
+ const url = rest.simplifyUrl(request.route, request.method);
304
+ if (request.runThroughQueue === false) {
305
+ await rest.sendRequest(request);
306
+ return;
764
307
  }
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
308
  const queue = rest.queues.get(url);
778
309
  if (queue !== undefined) {
779
310
  queue.makeRequest(request);
@@ -789,35 +320,14 @@ export function createRestManager(options) {
789
320
  rest.queues.set(url, bucketQueue);
790
321
  }
791
322
  },
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
- }));
323
+ async makeRequest (method, route, options) {
324
+ if (rest.isProxied) {
325
+ if (rest.authorization !== undefined) {
326
+ options ??= {};
327
+ options.headers ??= {};
328
+ options.headers.authorization = rest.authorization;
809
329
  }
810
- const headers = {
811
- Authorization: rest.authorization ?? ""
812
- };
813
- if (body) {
814
- headers['Content-Type'] = 'application/json';
815
- }
816
- const result = await fetch(`${rest.baseUrl}${url}`, {
817
- body: body ? JSON.stringify(body) : undefined,
818
- headers,
819
- method
820
- });
330
+ const result = await fetch(`${rest.baseUrl}/v${rest.version}${route}`, rest.createRequestBody(method, options));
821
331
  if (!result.ok) {
822
332
  const err = await result.json().catch(()=>{});
823
333
  // Legacy Handling to not break old code or when body is missing
@@ -826,38 +336,39 @@ export function createRestManager(options) {
826
336
  }
827
337
  return result.status !== 204 ? await result.json() : undefined;
828
338
  }
829
- return await new Promise((resolve, reject)=>{
339
+ // eslint-disable-next-line no-async-promise-executor
340
+ return await new Promise(async (resolve, reject)=>{
830
341
  const payload = {
831
- url,
342
+ route,
832
343
  method,
833
- body,
344
+ requestBodyOptions: options,
834
345
  retryCount: 0,
835
- retryRequest: async function(options) {
836
- rest.processRequest(payload);
346
+ retryRequest: async function(payload) {
347
+ await rest.processRequest(payload);
837
348
  },
838
349
  resolve: (data)=>{
839
350
  resolve(data.status !== 204 ? JSON.parse(data.body ?? '{}') : undefined);
840
351
  },
841
352
  reject,
842
- options
353
+ runThroughQueue: options?.runThroughQueue
843
354
  };
844
- rest.processRequest(payload);
355
+ await rest.processRequest(payload);
845
356
  });
846
357
  },
847
- async get (url) {
848
- return camelize(await rest.makeRequest('GET', url));
358
+ async get (url, options) {
359
+ return camelize(await rest.makeRequest('GET', url, options));
849
360
  },
850
- async post (url, body) {
851
- return camelize(await rest.makeRequest('POST', url, body));
361
+ async post (url, options) {
362
+ return camelize(await rest.makeRequest('POST', url, options));
852
363
  },
853
- async delete (url, body) {
854
- camelize(await rest.makeRequest('DELETE', url, body));
364
+ async delete (url, options) {
365
+ camelize(await rest.makeRequest('DELETE', url, options));
855
366
  },
856
- async patch (url, body) {
857
- return camelize(await rest.makeRequest('PATCH', url, body));
367
+ async patch (url, options) {
368
+ return camelize(await rest.makeRequest('PATCH', url, options));
858
369
  },
859
- async put (url, body, options) {
860
- return camelize(await rest.makeRequest('PUT', url, body, options));
370
+ async put (url, options) {
371
+ return camelize(await rest.makeRequest('PUT', url, options));
861
372
  },
862
373
  async addReaction (channelId, messageId, reaction) {
863
374
  reaction = processReactionString(reaction);
@@ -882,59 +393,101 @@ export function createRestManager(options) {
882
393
  async addThreadMember (channelId, userId) {
883
394
  await rest.put(rest.routes.channels.threads.user(channelId, userId));
884
395
  },
885
- async createAutomodRule (guildId, options) {
886
- return await rest.post(rest.routes.guilds.automod.rules(guildId), options);
396
+ async createAutomodRule (guildId, body, reason) {
397
+ return await rest.post(rest.routes.guilds.automod.rules(guildId), {
398
+ body,
399
+ reason
400
+ });
887
401
  },
888
- async createChannel (guildId, options) {
889
- return await rest.post(rest.routes.guilds.channels(guildId), options);
402
+ async createChannel (guildId, body, reason) {
403
+ return await rest.post(rest.routes.guilds.channels(guildId), {
404
+ body,
405
+ reason
406
+ });
890
407
  },
891
- async createEmoji (guildId, options) {
892
- return await rest.post(rest.routes.guilds.emojis(guildId), options);
408
+ async createEmoji (guildId, body, reason) {
409
+ return await rest.post(rest.routes.guilds.emojis(guildId), {
410
+ body,
411
+ reason
412
+ });
893
413
  },
894
- async createGlobalApplicationCommand (command) {
895
- return await rest.post(rest.routes.interactions.commands.commands(rest.applicationId), command);
414
+ async createGlobalApplicationCommand (body) {
415
+ return await rest.post(rest.routes.interactions.commands.commands(rest.applicationId), {
416
+ body
417
+ });
896
418
  },
897
- async createGuild (options) {
898
- return await rest.post(rest.routes.guilds.all(), options);
419
+ async createGuild (body) {
420
+ return await rest.post(rest.routes.guilds.all(), {
421
+ body
422
+ });
899
423
  },
900
- async createGuildApplicationCommand (command, guildId) {
901
- return await rest.post(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), command);
424
+ async createGuildApplicationCommand (body, guildId) {
425
+ return await rest.post(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), {
426
+ body
427
+ });
902
428
  },
903
- async createGuildFromTemplate (templateCode, options) {
904
- if (options.icon) {
905
- options.icon = await urlToBase64(options.icon);
429
+ async createGuildFromTemplate (templateCode, body) {
430
+ if (body.icon) {
431
+ body.icon = await urlToBase64(body.icon);
906
432
  }
907
- return await rest.post(rest.routes.guilds.templates.code(templateCode), options);
433
+ return await rest.post(rest.routes.guilds.templates.code(templateCode), {
434
+ body
435
+ });
908
436
  },
909
- async createGuildSticker (guildId, options) {
910
- return await rest.post(rest.routes.guilds.stickers(guildId), options);
437
+ async createGuildSticker (guildId, options, reason) {
438
+ const form = new FormData();
439
+ form.append('file', options.file.blob, options.file.name);
440
+ form.append('name', options.name);
441
+ form.append('description', options.description);
442
+ form.append('tags', options.tags);
443
+ return await rest.post(rest.routes.guilds.stickers(guildId), {
444
+ body: form,
445
+ reason
446
+ });
911
447
  },
912
- async createGuildTemplate (guildId, options) {
913
- return await rest.post(rest.routes.guilds.templates.all(guildId), options);
448
+ async createGuildTemplate (guildId, body) {
449
+ return await rest.post(rest.routes.guilds.templates.all(guildId), {
450
+ body
451
+ });
914
452
  },
915
- async createForumThread (channelId, options) {
916
- return await rest.post(rest.routes.channels.forum(channelId), options);
453
+ async createForumThread (channelId, body, reason) {
454
+ return await rest.post(rest.routes.channels.forum(channelId), {
455
+ body,
456
+ files: body.files,
457
+ reason
458
+ });
917
459
  },
918
- async createInvite (channelId, options = {}) {
919
- return await rest.post(rest.routes.channels.invites(channelId), options);
460
+ async createInvite (channelId, body = {}, reason) {
461
+ return await rest.post(rest.routes.channels.invites(channelId), {
462
+ body,
463
+ reason
464
+ });
920
465
  },
921
- async createRole (guildId, options, reason) {
466
+ async createRole (guildId, body, reason) {
922
467
  return await rest.post(rest.routes.guilds.roles.all(guildId), {
923
- ...options,
468
+ body,
924
469
  reason
925
470
  });
926
471
  },
927
- async createScheduledEvent (guildId, options) {
928
- return await rest.post(rest.routes.guilds.events.events(guildId), options);
472
+ async createScheduledEvent (guildId, body, reason) {
473
+ return await rest.post(rest.routes.guilds.events.events(guildId), {
474
+ body,
475
+ reason
476
+ });
929
477
  },
930
- async createStageInstance (options) {
931
- return await rest.post(rest.routes.channels.stages(), options);
478
+ async createStageInstance (body, reason) {
479
+ return await rest.post(rest.routes.channels.stages(), {
480
+ body,
481
+ reason
482
+ });
932
483
  },
933
- async createWebhook (channelId, options) {
484
+ async createWebhook (channelId, options, reason) {
934
485
  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
486
+ body: {
487
+ name: options.name,
488
+ avatar: options.avatar ? await urlToBase64(options.avatar) : undefined
489
+ },
490
+ reason
938
491
  });
939
492
  },
940
493
  async deleteAutomodRule (guildId, ruleId, reason) {
@@ -948,9 +501,9 @@ export function createRestManager(options) {
948
501
  });
949
502
  },
950
503
  async deleteChannelPermissionOverride (channelId, overwriteId, reason) {
951
- await rest.delete(rest.routes.channels.overwrite(channelId, overwriteId), reason ? {
504
+ await rest.delete(rest.routes.channels.overwrite(channelId, overwriteId), {
952
505
  reason
953
- } : undefined);
506
+ });
954
507
  },
955
508
  async deleteEmoji (guildId, id, reason) {
956
509
  await rest.delete(rest.routes.guilds.emoji(guildId, id), {
@@ -958,7 +511,9 @@ export function createRestManager(options) {
958
511
  });
959
512
  },
960
513
  async deleteFollowupMessage (token, messageId) {
961
- await rest.delete(rest.routes.interactions.responses.message(rest.applicationId, token, messageId));
514
+ await rest.delete(rest.routes.interactions.responses.message(rest.applicationId, token, messageId), {
515
+ unauthorized: true
516
+ });
962
517
  },
963
518
  async deleteGlobalApplicationCommand (commandId) {
964
519
  await rest.delete(rest.routes.interactions.commands.command(rest.applicationId, commandId));
@@ -970,20 +525,22 @@ export function createRestManager(options) {
970
525
  await rest.delete(rest.routes.interactions.commands.guilds.one(rest.applicationId, guildId, commandId));
971
526
  },
972
527
  async deleteGuildSticker (guildId, stickerId, reason) {
973
- await rest.delete(rest.routes.guilds.sticker(guildId, stickerId), reason ? {
528
+ await rest.delete(rest.routes.guilds.sticker(guildId, stickerId), {
974
529
  reason
975
- } : undefined);
530
+ });
976
531
  },
977
532
  async deleteGuildTemplate (guildId, templateCode) {
978
533
  await rest.delete(rest.routes.guilds.templates.guild(guildId, templateCode));
979
534
  },
980
- async deleteIntegration (guildId, integrationId) {
981
- await rest.delete(rest.routes.guilds.integration(guildId, integrationId));
535
+ async deleteIntegration (guildId, integrationId, reason) {
536
+ await rest.delete(rest.routes.guilds.integration(guildId, integrationId), {
537
+ reason
538
+ });
982
539
  },
983
540
  async deleteInvite (inviteCode, reason) {
984
- await rest.delete(rest.routes.guilds.invite(inviteCode), reason ? {
541
+ await rest.delete(rest.routes.guilds.invite(inviteCode), {
985
542
  reason
986
- } : undefined);
543
+ });
987
544
  },
988
545
  async deleteMessage (channelId, messageId, reason) {
989
546
  await rest.delete(rest.routes.channels.message(channelId, messageId), {
@@ -992,12 +549,16 @@ export function createRestManager(options) {
992
549
  },
993
550
  async deleteMessages (channelId, messageIds, reason) {
994
551
  await rest.post(rest.routes.channels.bulk(channelId), {
995
- messages: messageIds.slice(0, 100).map((id)=>id.toString()),
552
+ body: {
553
+ messages: messageIds.slice(0, 100).map((id)=>id.toString())
554
+ },
996
555
  reason
997
556
  });
998
557
  },
999
558
  async deleteOriginalInteractionResponse (token) {
1000
- await rest.delete(rest.routes.interactions.responses.original(rest.applicationId, token));
559
+ await rest.delete(rest.routes.interactions.responses.original(rest.applicationId, token), {
560
+ unauthorized: true
561
+ });
1001
562
  },
1002
563
  async deleteOwnReaction (channelId, messageId, reaction) {
1003
564
  reaction = processReactionString(reaction);
@@ -1010,16 +571,18 @@ export function createRestManager(options) {
1010
571
  reaction = processReactionString(reaction);
1011
572
  await rest.delete(rest.routes.channels.reactions.emoji(channelId, messageId, reaction));
1012
573
  },
1013
- async deleteRole (guildId, roleId) {
1014
- await rest.delete(rest.routes.guilds.roles.one(guildId, roleId));
574
+ async deleteRole (guildId, roleId, reason) {
575
+ await rest.delete(rest.routes.guilds.roles.one(guildId, roleId), {
576
+ reason
577
+ });
1015
578
  },
1016
579
  async deleteScheduledEvent (guildId, eventId) {
1017
580
  await rest.delete(rest.routes.guilds.events.event(guildId, eventId));
1018
581
  },
1019
582
  async deleteStageInstance (channelId, reason) {
1020
- await rest.delete(rest.routes.channels.stage(channelId), reason ? {
583
+ await rest.delete(rest.routes.channels.stage(channelId), {
1021
584
  reason
1022
- } : undefined);
585
+ });
1023
586
  },
1024
587
  async deleteUserReaction (channelId, messageId, userId, reaction) {
1025
588
  reaction = processReactionString(reaction);
@@ -1036,122 +599,195 @@ export function createRestManager(options) {
1036
599
  async deleteWebhookWithToken (webhookId, token) {
1037
600
  await rest.delete(rest.routes.webhooks.webhook(webhookId, token));
1038
601
  },
1039
- async editApplicationCommandPermissions (guildId, commandId, bearerToken, options) {
602
+ async editApplicationCommandPermissions (guildId, commandId, bearerToken, permissions) {
1040
603
  return await rest.put(rest.routes.interactions.commands.permission(rest.applicationId, guildId, commandId), {
1041
- permissions: options
1042
- }, {
604
+ body: {
605
+ permissions
606
+ },
1043
607
  headers: {
1044
608
  authorization: `Bearer ${bearerToken}`
1045
609
  }
1046
610
  });
1047
611
  },
1048
- async editAutomodRule (guildId, ruleId, options) {
1049
- return await rest.patch(rest.routes.guilds.automod.rule(guildId, ruleId), options);
612
+ async editAutomodRule (guildId, ruleId, body, reason) {
613
+ return await rest.patch(rest.routes.guilds.automod.rule(guildId, ruleId), {
614
+ body,
615
+ reason
616
+ });
1050
617
  },
1051
618
  async editBotProfile (options) {
1052
619
  const avatar = options?.botAvatarURL ? await urlToBase64(options?.botAvatarURL) : options?.botAvatarURL;
1053
620
  return await rest.patch(rest.routes.userBot(), {
1054
- username: options.username?.trim(),
1055
- avatar
621
+ body: {
622
+ username: options.username?.trim(),
623
+ avatar
624
+ }
1056
625
  });
1057
626
  },
1058
- async editChannel (channelId, options) {
1059
- return await rest.patch(rest.routes.channels.channel(channelId), options);
627
+ async editChannel (channelId, body, reason) {
628
+ return await rest.patch(rest.routes.channels.channel(channelId), {
629
+ body,
630
+ reason
631
+ });
1060
632
  },
1061
- async editChannelPermissionOverrides (channelId, options) {
1062
- await rest.put(rest.routes.channels.overwrite(channelId, options.id), options);
633
+ async editChannelPermissionOverrides (channelId, body, reason) {
634
+ await rest.put(rest.routes.channels.overwrite(channelId, body.id), {
635
+ body,
636
+ reason
637
+ });
1063
638
  },
1064
- async editChannelPositions (guildId, channelPositions) {
1065
- await rest.patch(rest.routes.guilds.channels(guildId), channelPositions);
639
+ async editChannelPositions (guildId, body) {
640
+ await rest.patch(rest.routes.guilds.channels(guildId), {
641
+ body
642
+ });
1066
643
  },
1067
- async editEmoji (guildId, id, options) {
1068
- return await rest.patch(rest.routes.guilds.emoji(guildId, id), options);
644
+ async editEmoji (guildId, id, body, reason) {
645
+ return await rest.patch(rest.routes.guilds.emoji(guildId, id), {
646
+ body,
647
+ reason
648
+ });
1069
649
  },
1070
- async editFollowupMessage (token, messageId, options) {
1071
- return await rest.patch(rest.routes.interactions.responses.message(rest.applicationId, token, messageId), options);
650
+ async editFollowupMessage (token, messageId, body) {
651
+ return await rest.patch(rest.routes.interactions.responses.message(rest.applicationId, token, messageId), {
652
+ body,
653
+ files: body.files,
654
+ unauthorized: true
655
+ });
1072
656
  },
1073
- async editGlobalApplicationCommand (commandId, options) {
1074
- return await rest.patch(rest.routes.interactions.commands.command(rest.applicationId, commandId), options);
657
+ async editGlobalApplicationCommand (commandId, body) {
658
+ return await rest.patch(rest.routes.interactions.commands.command(rest.applicationId, commandId), {
659
+ body
660
+ });
1075
661
  },
1076
- async editGuild (guildId, options) {
1077
- return await rest.patch(rest.routes.guilds.guild(guildId), options);
662
+ async editGuild (guildId, body, reason) {
663
+ return await rest.patch(rest.routes.guilds.guild(guildId), {
664
+ body,
665
+ reason
666
+ });
1078
667
  },
1079
- async editGuildApplicationCommand (commandId, guildId, options) {
1080
- return await rest.patch(rest.routes.interactions.commands.guilds.one(rest.applicationId, guildId, commandId), options);
668
+ async editGuildApplicationCommand (commandId, guildId, body) {
669
+ return await rest.patch(rest.routes.interactions.commands.guilds.one(rest.applicationId, guildId, commandId), {
670
+ body
671
+ });
1081
672
  },
1082
673
  async editGuildMfaLevel (guildId, mfaLevel, reason) {
1083
674
  await rest.post(rest.routes.guilds.mfa(guildId), {
1084
- level: mfaLevel,
675
+ body: {
676
+ level: mfaLevel
677
+ },
1085
678
  reason
1086
679
  });
1087
680
  },
1088
- async editGuildSticker (guildId, stickerId, options) {
1089
- return await rest.patch(rest.routes.guilds.sticker(guildId, stickerId), options);
681
+ async editGuildSticker (guildId, stickerId, body, reason) {
682
+ return await rest.patch(rest.routes.guilds.sticker(guildId, stickerId), {
683
+ body,
684
+ reason
685
+ });
1090
686
  },
1091
- async editGuildTemplate (guildId, templateCode, options) {
1092
- return await rest.patch(rest.routes.guilds.templates.guild(guildId, templateCode), options);
687
+ async editGuildTemplate (guildId, templateCode, body) {
688
+ return await rest.patch(rest.routes.guilds.templates.guild(guildId, templateCode), {
689
+ body
690
+ });
1093
691
  },
1094
- async editMessage (channelId, messageId, options) {
1095
- return await rest.patch(rest.routes.channels.message(channelId, messageId), options);
692
+ async editMessage (channelId, messageId, body) {
693
+ return await rest.patch(rest.routes.channels.message(channelId, messageId), {
694
+ body
695
+ });
1096
696
  },
1097
- async editOriginalInteractionResponse (token, options) {
1098
- return await rest.patch(rest.routes.interactions.responses.original(rest.applicationId, token), options);
697
+ async editOriginalInteractionResponse (token, body) {
698
+ return await rest.patch(rest.routes.interactions.responses.original(rest.applicationId, token), {
699
+ body,
700
+ files: body.files
701
+ });
1099
702
  },
1100
703
  async editOriginalWebhookMessage (webhookId, token, options) {
1101
704
  return await rest.patch(rest.routes.webhooks.original(webhookId, token, options), {
1102
- type: InteractionResponseTypes.UpdateMessage,
1103
- data: options
705
+ body: {
706
+ type: InteractionResponseTypes.UpdateMessage,
707
+ data: options
708
+ },
709
+ files: options.files,
710
+ unauthorized: true
1104
711
  });
1105
712
  },
1106
713
  async editOwnVoiceState (guildId, options) {
1107
714
  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
715
+ body: {
716
+ ...options,
717
+ request_to_speak_timestamp: options.requestToSpeakTimestamp ? new Date(options.requestToSpeakTimestamp).toISOString() : options.requestToSpeakTimestamp
718
+ }
1111
719
  });
1112
720
  },
1113
- async editScheduledEvent (guildId, eventId, options) {
1114
- return await rest.patch(rest.routes.guilds.events.event(guildId, eventId), options);
721
+ async editScheduledEvent (guildId, eventId, body, reason) {
722
+ return await rest.patch(rest.routes.guilds.events.event(guildId, eventId), {
723
+ body,
724
+ reason
725
+ });
1115
726
  },
1116
- async editRole (guildId, roleId, options) {
1117
- return await rest.patch(rest.routes.guilds.roles.one(guildId, roleId), options);
727
+ async editRole (guildId, roleId, body, reason) {
728
+ return await rest.patch(rest.routes.guilds.roles.one(guildId, roleId), {
729
+ body,
730
+ reason
731
+ });
1118
732
  },
1119
- async editRolePositions (guildId, options) {
1120
- return await rest.patch(rest.routes.guilds.roles.all(guildId), options);
733
+ async editRolePositions (guildId, body, reason) {
734
+ return await rest.patch(rest.routes.guilds.roles.all(guildId), {
735
+ body,
736
+ reason
737
+ });
1121
738
  },
1122
- async editStageInstance (channelId, data) {
739
+ async editStageInstance (channelId, topic, reason) {
1123
740
  return await rest.patch(rest.routes.channels.stage(channelId), {
1124
- topic: data.topic
741
+ body: {
742
+ topic
743
+ },
744
+ reason
1125
745
  });
1126
746
  },
1127
747
  async editUserVoiceState (guildId, options) {
1128
748
  await rest.patch(rest.routes.guilds.voice(guildId, options.userId), {
1129
- channel_id: options.channelId,
1130
- suppress: options.suppress,
1131
- user_id: options.userId
749
+ body: options
1132
750
  });
1133
751
  },
1134
- async editWebhook (webhookId, options) {
1135
- return await rest.patch(rest.routes.webhooks.id(webhookId), options);
752
+ async editWebhook (webhookId, body, reason) {
753
+ return await rest.patch(rest.routes.webhooks.id(webhookId), {
754
+ body,
755
+ reason
756
+ });
1136
757
  },
1137
758
  async editWebhookMessage (webhookId, token, messageId, options) {
1138
- return await rest.patch(rest.routes.webhooks.message(webhookId, token, messageId, options), options);
759
+ return await rest.patch(rest.routes.webhooks.message(webhookId, token, messageId, options), {
760
+ body: options,
761
+ files: options.files
762
+ });
1139
763
  },
1140
- async editWebhookWithToken (webhookId, token, options) {
1141
- return await rest.patch(rest.routes.webhooks.webhook(webhookId, token), options);
764
+ async editWebhookWithToken (webhookId, token, body) {
765
+ return await rest.patch(rest.routes.webhooks.webhook(webhookId, token), {
766
+ body
767
+ });
1142
768
  },
1143
- async editWelcomeScreen (guildId, options) {
1144
- return await rest.patch(rest.routes.guilds.welcome(guildId), options);
769
+ async editWelcomeScreen (guildId, body, reason) {
770
+ return await rest.patch(rest.routes.guilds.welcome(guildId), {
771
+ body,
772
+ reason
773
+ });
1145
774
  },
1146
- async editWidgetSettings (guildId, options) {
1147
- return await rest.patch(rest.routes.guilds.widget(guildId), options);
775
+ async editWidgetSettings (guildId, body, reason) {
776
+ return await rest.patch(rest.routes.guilds.widget(guildId), {
777
+ body,
778
+ reason
779
+ });
1148
780
  },
1149
781
  async executeWebhook (webhookId, token, options) {
1150
- return await rest.post(rest.routes.webhooks.webhook(webhookId, token, options), options);
782
+ return await rest.post(rest.routes.webhooks.webhook(webhookId, token, options), {
783
+ body: options
784
+ });
1151
785
  },
1152
786
  async followAnnouncement (sourceChannelId, targetChannelId) {
1153
787
  return await rest.post(rest.routes.channels.follow(sourceChannelId), {
1154
- webhook_channel_id: targetChannelId
788
+ body: {
789
+ webhook_channel_id: targetChannelId
790
+ }
1155
791
  });
1156
792
  },
1157
793
  async getActiveThreads (guildId) {
@@ -1198,7 +834,9 @@ export function createRestManager(options) {
1198
834
  },
1199
835
  async getDmChannel (userId) {
1200
836
  return await rest.post(rest.routes.channels.dm(), {
1201
- recipient_id: userId.toString()
837
+ body: {
838
+ recipient_id: userId
839
+ }
1202
840
  });
1203
841
  },
1204
842
  async getEmoji (guildId, emojiId) {
@@ -1208,7 +846,9 @@ export function createRestManager(options) {
1208
846
  return await rest.get(rest.routes.guilds.emojis(guildId));
1209
847
  },
1210
848
  async getFollowupMessage (token, messageId) {
1211
- return await rest.get(rest.routes.interactions.responses.message(rest.applicationId, token, messageId));
849
+ return await rest.get(rest.routes.interactions.responses.message(rest.applicationId, token, messageId), {
850
+ unauthorized: true
851
+ });
1212
852
  },
1213
853
  async getGatewayBot () {
1214
854
  return await rest.get(rest.routes.gatewayBot());
@@ -1261,7 +901,9 @@ export function createRestManager(options) {
1261
901
  return await rest.get(rest.routes.nitroStickerPacks());
1262
902
  },
1263
903
  async getOriginalInteractionResponse (token) {
1264
- return await rest.get(rest.routes.interactions.responses.original(rest.applicationId, token));
904
+ return await rest.get(rest.routes.interactions.responses.original(rest.applicationId, token), {
905
+ unauthorized: true
906
+ });
1265
907
  },
1266
908
  async getPinnedMessages (channelId) {
1267
909
  return await rest.get(rest.routes.channels.pins(channelId));
@@ -1362,61 +1004,58 @@ export function createRestManager(options) {
1362
1004
  await rest.delete(rest.routes.channels.threads.user(channelId, userId));
1363
1005
  },
1364
1006
  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
- });
1007
+ return await rest.post(rest.routes.webhooks.webhook(rest.applicationId, token), {
1008
+ body: options,
1009
+ files: options.files,
1010
+ unauthorized: true
1380
1011
  });
1381
1012
  },
1382
1013
  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
- });
1014
+ return await rest.post(rest.routes.interactions.responses.callback(interactionId, token), {
1015
+ body: options,
1016
+ files: options.data?.files,
1017
+ runThroughQueue: false,
1018
+ unauthorized: true
1398
1019
  });
1399
1020
  },
1400
- async sendMessage (channelId, options) {
1401
- return await rest.post(rest.routes.channels.messages(channelId), options);
1021
+ async sendMessage (channelId, body) {
1022
+ return await rest.post(rest.routes.channels.messages(channelId), {
1023
+ body,
1024
+ files: body.files
1025
+ });
1402
1026
  },
1403
- async startThreadWithMessage (channelId, messageId, options) {
1404
- return await rest.post(rest.routes.channels.threads.message(channelId, messageId), options);
1027
+ async startThreadWithMessage (channelId, messageId, body, reason) {
1028
+ return await rest.post(rest.routes.channels.threads.message(channelId, messageId), {
1029
+ body,
1030
+ reason
1031
+ });
1405
1032
  },
1406
- async startThreadWithoutMessage (channelId, options) {
1407
- return await rest.post(rest.routes.channels.threads.all(channelId), options);
1033
+ async startThreadWithoutMessage (channelId, body, reason) {
1034
+ return await rest.post(rest.routes.channels.threads.all(channelId), {
1035
+ body,
1036
+ reason
1037
+ });
1408
1038
  },
1409
1039
  async syncGuildTemplate (guildId) {
1410
1040
  return await rest.put(rest.routes.guilds.templates.all(guildId));
1411
1041
  },
1412
- async banMember (guildId, userId, options) {
1413
- await rest.put(rest.routes.guilds.members.ban(guildId, userId), options);
1042
+ async banMember (guildId, userId, body, reason) {
1043
+ await rest.put(rest.routes.guilds.members.ban(guildId, userId), {
1044
+ body,
1045
+ reason
1046
+ });
1414
1047
  },
1415
- async editBotMember (guildId, options) {
1416
- return await rest.patch(rest.routes.guilds.members.bot(guildId), options);
1048
+ async editBotMember (guildId, body, reason) {
1049
+ return await rest.patch(rest.routes.guilds.members.bot(guildId), {
1050
+ body,
1051
+ reason
1052
+ });
1417
1053
  },
1418
- async editMember (guildId, userId, options) {
1419
- return await rest.patch(rest.routes.guilds.members.member(guildId, userId), options);
1054
+ async editMember (guildId, userId, body, reason) {
1055
+ return await rest.patch(rest.routes.guilds.members.member(guildId, userId), {
1056
+ body,
1057
+ reason
1058
+ });
1420
1059
  },
1421
1060
  async getMember (guildId, userId) {
1422
1061
  return await rest.get(rest.routes.guilds.members.member(guildId, userId));
@@ -1430,35 +1069,70 @@ export function createRestManager(options) {
1430
1069
  });
1431
1070
  },
1432
1071
  async pinMessage (channelId, messageId, reason) {
1433
- await rest.put(rest.routes.channels.pin(channelId, messageId), reason ? {
1072
+ await rest.put(rest.routes.channels.pin(channelId, messageId), {
1434
1073
  reason
1435
- } : undefined);
1074
+ });
1436
1075
  },
1437
- async pruneMembers (guildId, options) {
1438
- return await rest.post(rest.routes.guilds.members.prune(guildId), options);
1076
+ async pruneMembers (guildId, body, reason) {
1077
+ return await rest.post(rest.routes.guilds.members.prune(guildId), {
1078
+ body,
1079
+ reason
1080
+ });
1439
1081
  },
1440
1082
  async searchMembers (guildId, query, options) {
1441
1083
  return await rest.get(rest.routes.guilds.members.search(guildId, query, options));
1442
1084
  },
1443
- async unbanMember (guildId, userId) {
1444
- await rest.delete(rest.routes.guilds.members.ban(guildId, userId));
1085
+ async unbanMember (guildId, userId, reason) {
1086
+ await rest.delete(rest.routes.guilds.members.ban(guildId, userId), {
1087
+ reason
1088
+ });
1445
1089
  },
1446
1090
  async unpinMessage (channelId, messageId, reason) {
1447
- await rest.delete(rest.routes.channels.pin(channelId, messageId), reason ? {
1091
+ await rest.delete(rest.routes.channels.pin(channelId, messageId), {
1448
1092
  reason
1449
- } : undefined);
1093
+ });
1450
1094
  },
1451
1095
  async triggerTypingIndicator (channelId) {
1452
1096
  await rest.post(rest.routes.channels.typing(channelId));
1453
1097
  },
1454
- async upsertGlobalApplicationCommands (commands) {
1455
- return await rest.put(rest.routes.interactions.commands.commands(rest.applicationId), commands);
1098
+ async upsertGlobalApplicationCommands (body) {
1099
+ return await rest.put(rest.routes.interactions.commands.commands(rest.applicationId), {
1100
+ body
1101
+ });
1102
+ },
1103
+ async upsertGuildApplicationCommands (guildId, body) {
1104
+ return await rest.put(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), {
1105
+ body
1106
+ });
1456
1107
  },
1457
- async upsertGuildApplicationCommands (guildId, commands) {
1458
- return await rest.put(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), commands);
1108
+ preferSnakeCase (enabled) {
1109
+ const camelizer = enabled ? (x)=>x : camelize;
1110
+ rest.get = async (url, options)=>{
1111
+ return camelizer(await rest.makeRequest('GET', url, options));
1112
+ };
1113
+ rest.post = async (url, options)=>{
1114
+ return camelizer(await rest.makeRequest('POST', url, options));
1115
+ };
1116
+ rest.delete = async (url, options)=>{
1117
+ camelizer(await rest.makeRequest('DELETE', url, options));
1118
+ };
1119
+ rest.patch = async (url, options)=>{
1120
+ return camelizer(await rest.makeRequest('PATCH', url, options));
1121
+ };
1122
+ rest.put = async (url, options)=>{
1123
+ return camelizer(await rest.makeRequest('PUT', url, options));
1124
+ };
1125
+ return rest;
1459
1126
  }
1460
1127
  };
1461
1128
  return rest;
1462
1129
  }
1130
+ var HttpResponseCode;
1131
+ (function(HttpResponseCode) {
1132
+ HttpResponseCode[HttpResponseCode[/** Minimum value of a code in oder to consider that it was successful. */ "Success"] = 200] = "Success";
1133
+ HttpResponseCode[HttpResponseCode[/** Request completed successfully, but Discord returned an empty body. */ "NoContent"] = 204] = "NoContent";
1134
+ HttpResponseCode[HttpResponseCode[/** Minimum value of a code in order to consider that something went wrong. */ "Error"] = 400] = "Error";
1135
+ HttpResponseCode[HttpResponseCode[/** This request got rate limited. */ "TooManyRequests"] = 429] = "TooManyRequests";
1136
+ })(HttpResponseCode || (HttpResponseCode = {}));
1463
1137
 
1464
1138
  //# sourceMappingURL=manager.js.map