@discordeno/rest 19.0.0-next.c9c510b → 19.0.0-next.cb4f097

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.
@@ -1 +1 @@
1
- {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"AAkDA,OAAO,KAAK,EAA4B,wBAAwB,EAAE,WAAW,EAAsB,MAAM,YAAY,CAAA;AAKrH,eAAO,MAAM,mBAAmB,KAAK,CAAA;AACrC,eAAO,MAAM,eAAe,4BAA4B,CAAA;AAExD,eAAO,MAAM,uBAAuB,uBAAuB,CAAA;AAC3D,eAAO,MAAM,2BAA2B,0BAA0B,CAAA;AAClE,eAAO,MAAM,6BAA6B,4BAA4B,CAAA;AACtE,eAAO,MAAM,wBAAwB,uBAAuB,CAAA;AAC5D,eAAO,MAAM,wBAAwB,uBAAuB,CAAA;AAC5D,eAAO,MAAM,uBAAuB,sBAAsB,CAAA;AAC1D,eAAO,MAAM,uBAAuB,sBAAsB,CAAA;AAE1D,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,WAAW,CAuqChF"}
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"AAyDA,OAAO,KAAK,EAA4B,wBAAwB,EAAsB,WAAW,EAAsB,MAAM,YAAY,CAAA;AAKzI,eAAO,MAAM,mBAAmB,KAAK,CAAA;AACrC,eAAO,MAAM,eAAe,4BAA4B,CAAA;AAExD,eAAO,MAAM,uBAAuB,uBAAuB,CAAA;AAC3D,eAAO,MAAM,2BAA2B,0BAA0B,CAAA;AAClE,eAAO,MAAM,6BAA6B,4BAA4B,CAAA;AACtE,eAAO,MAAM,wBAAwB,uBAAuB,CAAA;AAC5D,eAAO,MAAM,wBAAwB,uBAAuB,CAAA;AAC5D,eAAO,MAAM,uBAAuB,sBAAsB,CAAA;AAC1D,eAAO,MAAM,uBAAuB,sBAAsB,CAAA;AAE1D,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,WAAW,CAk3ChF"}
package/dist/manager.js CHANGED
@@ -1,4 +1,5 @@
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';
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';
2
3
  import { createInvalidRequestBucket } from './invalidBucket.js';
3
4
  import { Queue } from './queue.js';
4
5
  import { InteractionResponseTypes } from '@discordeno/types';
@@ -35,8 +36,14 @@ export function createRestManager(options) {
35
36
  token: options.token,
36
37
  version: options.version ?? DISCORD_API_VERSION,
37
38
  routes: createRoutes(),
38
- checkRateLimits (url) {
39
- const ratelimited = rest.rateLimitedPaths.get(url);
39
+ createBaseHeaders () {
40
+ return {
41
+ 'user-agent': `DiscordBot (https://github.com/discordeno/discordeno, v${version})`
42
+ };
43
+ },
44
+ checkRateLimits (url, headers) {
45
+ const authHeader = headers?.authorization ?? '';
46
+ const ratelimited = rest.rateLimitedPaths.get(`${authHeader}${url}`);
40
47
  const global = rest.rateLimitedPaths.get('global');
41
48
  const now = Date.now();
42
49
  if (ratelimited && now < ratelimited.resetTimestamp) {
@@ -62,10 +69,10 @@ export function createRestManager(options) {
62
69
  case 'permissions':
63
70
  case 'allow':
64
71
  case 'deny':
65
- newObj[key] = calculateBits(value);
72
+ newObj[key] = typeof value === 'string' ? value : calculateBits(value);
66
73
  continue;
67
74
  case 'defaultMemberPermissions':
68
- newObj.default_member_permissions = calculateBits(value);
75
+ newObj.default_member_permissions = typeof value === 'string' ? value : calculateBits(value);
69
76
  continue;
70
77
  case 'nameLocalizations':
71
78
  newObj.name_localizations = value;
@@ -83,10 +90,8 @@ export function createRestManager(options) {
83
90
  return obj;
84
91
  },
85
92
  createRequestBody (method, options) {
86
- const headers = {
87
- 'user-agent': `DiscordBot (https://github.com/discordeno/discordeno, v${version})`
88
- };
89
- if (options?.unauthorized !== false) headers.authorization = `Bot ${rest.token}`;
93
+ const headers = this.createBaseHeaders();
94
+ if (options?.unauthorized !== true) headers.authorization = `Bot ${rest.token}`;
90
95
  // IF A REASON IS PROVIDED ENCODE IT IN HEADERS
91
96
  if (options?.reason !== undefined) {
92
97
  headers[AUDIT_LOG_REASON_HEADER] = encodeURIComponent(options?.reason);
@@ -100,12 +105,21 @@ export function createRestManager(options) {
100
105
  for(let i = 0; i < options.files.length; ++i){
101
106
  form.append(`file${i}`, options.files[i].blob, options.files[i].name);
102
107
  }
103
- form.append('payload_json', JSON.stringify({
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({
104
110
  ...options.body,
105
111
  files: undefined
106
- }));
112
+ })));
113
+ // No need to set the `content-type` header since `fetch` does that automatically for us when we use a `FormData` object.
107
114
  body = form;
108
- // No need to set the `content-type` header since `fetch` does that automatically for us when we use a `FormData` object.
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('&');
109
123
  } else if (options?.body !== undefined) {
110
124
  if (options.body instanceof FormData) {
111
125
  body = options.body;
@@ -152,7 +166,7 @@ export function createRestManager(options) {
152
166
  }, 1000);
153
167
  }
154
168
  },
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) {
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) {
156
170
  let rateLimited = false;
157
171
  // GET ALL NECESSARY HEADERS
158
172
  const remaining = headers.get(RATE_LIMIT_REMAINING_HEADER);
@@ -162,7 +176,7 @@ export function createRestManager(options) {
162
176
  // undefined override null needed for typings
163
177
  const bucketId = headers.get(RATE_LIMIT_BUCKET_HEADER) ?? undefined;
164
178
  const limit = headers.get(RATE_LIMIT_LIMIT_HEADER);
165
- rest.queues.get(url)?.handleCompletedRequest({
179
+ rest.queues.get(`${requestAuthorization}${url}`)?.handleCompletedRequest({
166
180
  remaining: remaining ? Number(remaining) : undefined,
167
181
  interval: retryAfter ? Number(retryAfter) * 1000 : undefined,
168
182
  max: limit ? Number(limit) : undefined
@@ -171,14 +185,14 @@ export function createRestManager(options) {
171
185
  if (remaining === '0') {
172
186
  rateLimited = true;
173
187
  // SAVE THE URL AS LIMITED, IMPORTANT FOR NEW REQUESTS BY USER WITHOUT BUCKET
174
- rest.rateLimitedPaths.set(url, {
188
+ rest.rateLimitedPaths.set(`${requestAuthorization}${url}`, {
175
189
  url,
176
190
  resetTimestamp: reset,
177
191
  bucketId
178
192
  });
179
193
  // SAVE THE BUCKET AS LIMITED SINCE DIFFERENT URLS MAY SHARE A BUCKET
180
194
  if (bucketId) {
181
- rest.rateLimitedPaths.set(bucketId, {
195
+ rest.rateLimitedPaths.set(`${requestAuthorization}${bucketId}`, {
182
196
  url,
183
197
  resetTimestamp: reset,
184
198
  bucketId
@@ -187,8 +201,8 @@ export function createRestManager(options) {
187
201
  }
188
202
  // IF THERE IS NO REMAINING GLOBAL LIMIT, MARK IT RATE LIMITED GLOBALLY
189
203
  if (global) {
190
- const retryAfter = headers.get('retry-after');
191
- const globalReset = Date.now() + Number(retryAfter) * 1000;
204
+ const retryAfter = Number(headers.get('retry-after')) * 1000;
205
+ const globalReset = Date.now() + retryAfter;
192
206
  // rest.debug(
193
207
  // `[REST = Globally Rate Limited] URL: ${url} | Global Rest: ${globalReset}`
194
208
  // )
@@ -196,14 +210,14 @@ export function createRestManager(options) {
196
210
  rateLimited = true;
197
211
  setTimeout(()=>{
198
212
  rest.globallyRateLimited = false;
199
- }, globalReset);
213
+ }, retryAfter);
200
214
  rest.rateLimitedPaths.set('global', {
201
215
  url: 'global',
202
216
  resetTimestamp: globalReset,
203
217
  bucketId
204
218
  });
205
219
  if (bucketId) {
206
- rest.rateLimitedPaths.set(bucketId, {
220
+ rest.rateLimitedPaths.set(`${requestAuthorization}${bucketId}`, {
207
221
  url: 'global',
208
222
  resetTimestamp: globalReset,
209
223
  bucketId
@@ -218,12 +232,16 @@ export function createRestManager(options) {
218
232
  async sendRequest (options) {
219
233
  const url = `${rest.baseUrl}/v${rest.version}${options.route}`;
220
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
+ }
221
242
  logger.debug(`sending request to ${url}`, 'with payload:', {
222
243
  ...payload,
223
- headers: {
224
- ...payload.headers,
225
- authorization: 'Bot tokenhere'
226
- }
244
+ headers: loggingHeaders
227
245
  });
228
246
  const response = await fetch(url, payload).catch(async (error)=>{
229
247
  logger.error(error);
@@ -240,7 +258,7 @@ export function createRestManager(options) {
240
258
  // Mark request and completed
241
259
  rest.invalidBucket.handleCompletedRequest(response.status, response.headers.get(RATE_LIMIT_SCOPE_HEADER) === 'shared');
242
260
  // Set the bucket id if it was available on the headers
243
- const bucketId = rest.processHeaders(rest.simplifyUrl(options.route, options.method), response.headers);
261
+ const bucketId = rest.processHeaders(rest.simplifyUrl(options.route, options.method), response.headers, authenticationScheme === 'Bearer' ? payload.headers.authorization : '');
244
262
  if (bucketId) options.bucketId = bucketId;
245
263
  if (response.status < 200 || response.status >= 400) {
246
264
  logger.debug(`Request to ${url} failed.`);
@@ -305,19 +323,21 @@ export function createRestManager(options) {
305
323
  await rest.sendRequest(request);
306
324
  return;
307
325
  }
308
- const queue = rest.queues.get(url);
326
+ const authHeader = request.requestBodyOptions?.headers?.authorization ?? '';
327
+ const queue = rest.queues.get(`${authHeader}${url}`);
309
328
  if (queue !== undefined) {
310
329
  queue.makeRequest(request);
311
330
  } else {
312
331
  // CREATES A NEW QUEUE
313
332
  const bucketQueue = new Queue(rest, {
314
333
  url,
315
- deleteQueueDelay: rest.deleteQueueDelay
334
+ deleteQueueDelay: rest.deleteQueueDelay,
335
+ authentication: authHeader
316
336
  });
317
337
  // Add request to queue
318
338
  bucketQueue.makeRequest(request);
319
339
  // Save queue
320
- rest.queues.set(url, bucketQueue);
340
+ rest.queues.set(`${authHeader}${url}`, bucketQueue);
321
341
  }
322
342
  },
323
343
  async makeRequest (method, route, options) {
@@ -393,6 +413,11 @@ export function createRestManager(options) {
393
413
  async addThreadMember (channelId, userId) {
394
414
  await rest.put(rest.routes.channels.threads.user(channelId, userId));
395
415
  },
416
+ async addDmRecipient (channelId, userId, body) {
417
+ await rest.put(rest.routes.channels.dmRecipient(channelId, userId), {
418
+ body
419
+ });
420
+ },
396
421
  async createAutomodRule (guildId, body, reason) {
397
422
  return await rest.post(rest.routes.guilds.automod.rules(guildId), {
398
423
  body,
@@ -411,20 +436,34 @@ export function createRestManager(options) {
411
436
  reason
412
437
  });
413
438
  },
414
- async createGlobalApplicationCommand (body) {
415
- return await rest.post(rest.routes.interactions.commands.commands(rest.applicationId), {
439
+ async createGlobalApplicationCommand (body, options) {
440
+ const restOptions = {
416
441
  body
417
- });
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);
418
450
  },
419
451
  async createGuild (body) {
420
452
  return await rest.post(rest.routes.guilds.all(), {
421
453
  body
422
454
  });
423
455
  },
424
- async createGuildApplicationCommand (body, guildId) {
425
- return await rest.post(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), {
456
+ async createGuildApplicationCommand (body, guildId, options) {
457
+ const restOptions = {
426
458
  body
427
- });
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);
428
467
  },
429
468
  async createGuildFromTemplate (templateCode, body) {
430
469
  if (body.icon) {
@@ -617,7 +656,7 @@ export function createRestManager(options) {
617
656
  },
618
657
  async editBotProfile (options) {
619
658
  const avatar = options?.botAvatarURL ? await urlToBase64(options?.botAvatarURL) : options?.botAvatarURL;
620
- return await rest.patch(rest.routes.userBot(), {
659
+ return await rest.patch(rest.routes.currentUser(), {
621
660
  body: {
622
661
  username: options.username?.trim(),
623
662
  avatar
@@ -691,7 +730,8 @@ export function createRestManager(options) {
691
730
  },
692
731
  async editMessage (channelId, messageId, body) {
693
732
  return await rest.patch(rest.routes.channels.message(channelId, messageId), {
694
- body
733
+ body,
734
+ files: body.files
695
735
  });
696
736
  },
697
737
  async editOriginalInteractionResponse (token, body) {
@@ -793,14 +833,60 @@ export function createRestManager(options) {
793
833
  async getActiveThreads (guildId) {
794
834
  return await rest.get(rest.routes.channels.threads.active(guildId));
795
835
  },
796
- async getApplicationCommandPermission (guildId, commandId) {
797
- return await rest.get(rest.routes.interactions.commands.permission(rest.applicationId, guildId, commandId));
798
- },
799
- async getApplicationCommandPermissions (guildId) {
800
- 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);
801
855
  },
802
856
  async getApplicationInfo () {
803
- 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
+ });
804
890
  },
805
891
  async getAuditLog (guildId, options) {
806
892
  return await rest.get(rest.routes.guilds.auditlogs(guildId, options));
@@ -839,6 +925,11 @@ export function createRestManager(options) {
839
925
  }
840
926
  });
841
927
  },
928
+ async getGroupDmChannel (body) {
929
+ return await rest.post(rest.routes.channels.dm(), {
930
+ body
931
+ });
932
+ },
842
933
  async getEmoji (guildId, emojiId) {
843
934
  return await rest.get(rest.routes.guilds.emoji(guildId, emojiId));
844
935
  },
@@ -864,6 +955,14 @@ export function createRestManager(options) {
864
955
  }) {
865
956
  return await rest.get(rest.routes.guilds.guild(guildId, options.counts));
866
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
+ },
867
966
  async getGuildApplicationCommand (commandId, guildId) {
868
967
  return await rest.get(rest.routes.interactions.commands.guilds.one(rest.applicationId, guildId, commandId));
869
968
  },
@@ -959,6 +1058,30 @@ export function createRestManager(options) {
959
1058
  async getUser (id) {
960
1059
  return await rest.get(rest.routes.user(id));
961
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
+ },
962
1085
  async getVanityUrl (guildId) {
963
1086
  return await rest.get(rest.routes.guilds.vanity(guildId));
964
1087
  },
@@ -1003,6 +1126,9 @@ export function createRestManager(options) {
1003
1126
  async removeThreadMember (channelId, userId) {
1004
1127
  await rest.delete(rest.routes.channels.threads.user(channelId, userId));
1005
1128
  },
1129
+ async removeDmRecipient (channelId, userId) {
1130
+ await rest.delete(rest.routes.channels.dmRecipient(channelId, userId));
1131
+ },
1006
1132
  async sendFollowupMessage (token, options) {
1007
1133
  return await rest.post(rest.routes.webhooks.webhook(rest.applicationId, token), {
1008
1134
  body: options,
@@ -1060,6 +1186,14 @@ export function createRestManager(options) {
1060
1186
  async getMember (guildId, userId) {
1061
1187
  return await rest.get(rest.routes.guilds.members.member(guildId, userId));
1062
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
+ },
1063
1197
  async getMembers (guildId, options) {
1064
1198
  return await rest.get(rest.routes.guilds.members.members(guildId, options));
1065
1199
  },
@@ -1095,13 +1229,41 @@ export function createRestManager(options) {
1095
1229
  async triggerTypingIndicator (channelId) {
1096
1230
  await rest.post(rest.routes.channels.typing(channelId));
1097
1231
  },
1098
- async upsertGlobalApplicationCommands (body) {
1099
- return await rest.put(rest.routes.interactions.commands.commands(rest.applicationId), {
1232
+ async upsertGlobalApplicationCommands (body, options) {
1233
+ const restOptions = {
1100
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
1101
1263
  });
1102
1264
  },
1103
- async upsertGuildApplicationCommands (guildId, body) {
1104
- return await rest.put(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), {
1265
+ async addGuildMember (guildId, userId, body) {
1266
+ return await rest.put(rest.routes.guilds.members.member(guildId, userId), {
1105
1267
  body
1106
1268
  });
1107
1269
  },