@discordeno/rest 19.0.0-next.9fad360 → 19.0.0-next.a087a52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/invalidBucket.js +6 -6
- package/dist/invalidBucket.js.map +1 -1
- package/dist/manager.d.ts.map +1 -1
- package/dist/manager.js +60 -23
- package/dist/manager.js.map +1 -1
- package/dist/routes.js +1 -1
- package/dist/routes.js.map +1 -1
- package/dist/types.d.ts +8 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +4 -5
package/dist/invalidBucket.js
CHANGED
|
@@ -21,7 +21,7 @@ import { delay, logger } from '@discordeno/utils';
|
|
|
21
21
|
processing: false,
|
|
22
22
|
waiting: [],
|
|
23
23
|
requestsAllowed: function() {
|
|
24
|
-
if (bucket.resetAt !== undefined && Date.now()
|
|
24
|
+
if (bucket.resetAt !== undefined && Date.now() >= bucket.resetAt) {
|
|
25
25
|
bucket.invalidRequests = 0;
|
|
26
26
|
bucket.resetAt = Date.now() + bucket.interval;
|
|
27
27
|
}
|
|
@@ -45,14 +45,13 @@ import { delay, logger } from '@discordeno/utils';
|
|
|
45
45
|
},
|
|
46
46
|
processWaiting: async function() {
|
|
47
47
|
// If already processing, that loop will handle all waiting requests.
|
|
48
|
-
if (bucket.processing)
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
48
|
+
if (bucket.processing) return;
|
|
51
49
|
// Mark as processing so other loops don't start
|
|
52
50
|
bucket.processing = true;
|
|
53
51
|
while(bucket.waiting.length > 0){
|
|
54
|
-
logger.info(`[InvalidBucket] processing waiting queue while loop ran with ${bucket.waiting.length}
|
|
55
|
-
if (bucket.resetAt !== undefined
|
|
52
|
+
logger.info(`[InvalidBucket] processing waiting queue while loop ran with ${bucket.waiting.length} pending requests to be made. ${JSON.stringify(bucket)}`);
|
|
53
|
+
if (!bucket.isRequestAllowed() && bucket.resetAt !== undefined) {
|
|
54
|
+
logger.warn(`[InvalidBucket] processing waiting queue is now paused until more requests are available. ${bucket.waiting.length} pending requests. ${JSON.stringify(bucket)}`);
|
|
56
55
|
await delay(bucket.resetAt - Date.now());
|
|
57
56
|
}
|
|
58
57
|
bucket.activeRequests += 1;
|
|
@@ -74,6 +73,7 @@ import { delay, logger } from '@discordeno/utils';
|
|
|
74
73
|
bucket.resetAt = Date.now() + bucket.interval;
|
|
75
74
|
}
|
|
76
75
|
bucket.invalidRequests += 1;
|
|
76
|
+
logger.warn(`[InvalidBucket] an invalid request was made. Increasing invalidRequests count to ${bucket.invalidRequests}`);
|
|
77
77
|
}
|
|
78
78
|
};
|
|
79
79
|
return bucket;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/invalidBucket.ts"],"sourcesContent":["import { delay, logger } from '@discordeno/utils'\n\n/**\n * A invalid request bucket is used in a similar manner as a leaky bucket but a invalid request bucket can be refilled as needed.\n * It's purpose is to make sure the bot does not hit the limit to getting a 1 hr ban.\n *\n * @param options The options used to configure this bucket.\n * @returns RefillingBucket\n */\nexport function createInvalidRequestBucket(options: InvalidRequestBucketOptions): InvalidRequestBucket {\n const bucket: InvalidRequestBucket = {\n invalidRequests: options.current ?? 0,\n max: options.max ?? 10000,\n interval: options.interval ?? 600_000, // 10 minutes\n resetAt: options.resetAt,\n safety: options.safety ?? 1,\n errorStatuses: options.errorStatuses ?? [401, 403, 429],\n activeRequests: options.requested ?? 0,\n processing: false,\n\n waiting: [],\n\n requestsAllowed: function () {\n if (bucket.resetAt !== undefined && Date.now()
|
|
1
|
+
{"version":3,"sources":["../src/invalidBucket.ts"],"sourcesContent":["import { delay, logger } from '@discordeno/utils'\n\n/**\n * A invalid request bucket is used in a similar manner as a leaky bucket but a invalid request bucket can be refilled as needed.\n * It's purpose is to make sure the bot does not hit the limit to getting a 1 hr ban.\n *\n * @param options The options used to configure this bucket.\n * @returns RefillingBucket\n */\nexport function createInvalidRequestBucket(options: InvalidRequestBucketOptions): InvalidRequestBucket {\n const bucket: InvalidRequestBucket = {\n invalidRequests: options.current ?? 0,\n max: options.max ?? 10000,\n interval: options.interval ?? 600_000, // 10 minutes\n resetAt: options.resetAt,\n safety: options.safety ?? 1,\n errorStatuses: options.errorStatuses ?? [401, 403, 429],\n activeRequests: options.requested ?? 0,\n processing: false,\n\n waiting: [],\n\n requestsAllowed: function () {\n if (bucket.resetAt !== undefined && Date.now() >= bucket.resetAt) {\n bucket.invalidRequests = 0\n bucket.resetAt = Date.now() + bucket.interval\n }\n\n return bucket.max - bucket.invalidRequests - bucket.activeRequests - bucket.safety\n },\n\n isRequestAllowed: function () {\n return bucket.requestsAllowed() > 0\n },\n\n waitUntilRequestAvailable: async function () {\n // eslint-disable-next-line no-async-promise-executor\n return await new Promise(async (resolve) => {\n // If whatever amount of requests is left is more than the safety margin, allow the request\n if (bucket.isRequestAllowed()) {\n bucket.activeRequests += 1\n resolve()\n } else {\n bucket.waiting.push(resolve)\n await bucket.processWaiting()\n }\n })\n },\n\n processWaiting: async function () {\n // If already processing, that loop will handle all waiting requests.\n if (bucket.processing) return\n\n // Mark as processing so other loops don't start\n bucket.processing = true\n\n while (bucket.waiting.length > 0) {\n logger.info(`[InvalidBucket] processing waiting queue while loop ran with ${bucket.waiting.length} pending requests to be made. ${JSON.stringify(bucket)}`)\n\n if (!bucket.isRequestAllowed() && bucket.resetAt !== undefined) {\n logger.warn(`[InvalidBucket] processing waiting queue is now paused until more requests are available. ${bucket.waiting.length} pending requests. ${JSON.stringify(bucket)}`)\n await delay(bucket.resetAt - Date.now())\n }\n\n bucket.activeRequests += 1\n // Resolve the next item in the queue\n bucket.waiting.shift()?.()\n }\n\n // Mark as false so next pending request can be triggered by new loop.\n bucket.processing = false\n },\n\n handleCompletedRequest: function (code, sharedScope) {\n // Since request is complete, we can remove one from requested.\n bucket.activeRequests -= 1\n // Since it is as a valid request, we don't need to do anything\n if (!bucket.errorStatuses.includes(code)) return\n // Shared scope is not considered invalid\n if (code === 429 && sharedScope) return\n\n // INVALID REQUEST WAS MADE\n if (bucket.resetAt === undefined) {\n bucket.resetAt = Date.now() + bucket.interval\n }\n\n bucket.invalidRequests += 1\n logger.warn(`[InvalidBucket] an invalid request was made. Increasing invalidRequests count to ${bucket.invalidRequests}`)\n },\n }\n\n return bucket\n}\n\nexport interface InvalidRequestBucketOptions {\n /** current invalid amount */\n current?: number\n /** max invalid requests allowed until ban. Defaults to 10,000 */\n max?: number\n /** The time that discord allows to make the max number of invalid requests. Defaults to 10 minutes */\n interval?: number\n /** When the timeout for the bucket has started at. */\n resetAt?: number\n /** how safe to be from max. Defaults to 1 */\n safety?: number\n /** The request statuses that count as an invalid request. */\n errorStatuses?: number[]\n /** The amount of requests that were requested from this bucket. */\n requested?: number\n}\n\nexport interface InvalidRequestBucket {\n /** current invalid amount */\n invalidRequests: number\n /** max invalid requests allowed until ban. Defaults to 10,000 */\n max: number\n /** The time that discord allows to make the max number of invalid requests. Defaults to 10 minutes */\n interval: number\n /** When the timeout for this bucket has started at. */\n resetAt: number | undefined\n /** how safe to be from max. Defaults to 1 */\n safety: number\n /** The request statuses that count as an invalid request. */\n errorStatuses: number[]\n /** The amount of requests that were requested from this bucket. */\n activeRequests: number\n /** The requests that are currently pending. */\n waiting: Array<(value: void | PromiseLike<void>) => void>\n /** Whether or not the waiting queue is already processing. */\n processing: boolean\n\n /** Gives the number of requests that are currently allowed. */\n requestsAllowed: () => number\n /** Checks if a request is allowed at this time. */\n isRequestAllowed: () => boolean\n /** Waits until a request is available */\n waitUntilRequestAvailable: () => Promise<void>\n /** Begins processing the waiting queue of requests. */\n processWaiting: () => Promise<void>\n /** Handler for whenever a request is validated. This should update the requested values or trigger any other necessary stuff. */\n handleCompletedRequest: (code: number, sharedScope: boolean) => void\n}\n"],"names":["delay","logger","createInvalidRequestBucket","options","bucket","invalidRequests","current","max","interval","resetAt","safety","errorStatuses","activeRequests","requested","processing","waiting","requestsAllowed","undefined","Date","now","isRequestAllowed","waitUntilRequestAvailable","Promise","resolve","push","processWaiting","length","info","JSON","stringify","warn","shift","handleCompletedRequest","code","sharedScope","includes"],"mappings":"AAAA,SAASA,KAAK,EAAEC,MAAM,QAAQ,oBAAmB;AAEjD;;;;;;CAMC,GACD,OAAO,SAASC,2BAA2BC,OAAoC,EAAwB;IACrG,MAAMC,SAA+B;QACnCC,iBAAiBF,QAAQG,OAAO,IAAI;QACpCC,KAAKJ,QAAQI,GAAG,IAAI;QACpBC,UAAUL,QAAQK,QAAQ,IAAI;QAC9BC,SAASN,QAAQM,OAAO;QACxBC,QAAQP,QAAQO,MAAM,IAAI;QAC1BC,eAAeR,QAAQQ,aAAa,IAAI;YAAC;YAAK;YAAK;SAAI;QACvDC,gBAAgBT,QAAQU,SAAS,IAAI;QACrCC,YAAY,KAAK;QAEjBC,SAAS,EAAE;QAEXC,iBAAiB,WAAY;YAC3B,IAAIZ,OAAOK,OAAO,KAAKQ,aAAaC,KAAKC,GAAG,MAAMf,OAAOK,OAAO,EAAE;gBAChEL,OAAOC,eAAe,GAAG;gBACzBD,OAAOK,OAAO,GAAGS,KAAKC,GAAG,KAAKf,OAAOI,QAAQ;YAC/C,CAAC;YAED,OAAOJ,OAAOG,GAAG,GAAGH,OAAOC,eAAe,GAAGD,OAAOQ,cAAc,GAAGR,OAAOM,MAAM;QACpF;QAEAU,kBAAkB,WAAY;YAC5B,OAAOhB,OAAOY,eAAe,KAAK;QACpC;QAEAK,2BAA2B,iBAAkB;YAC3C,qDAAqD;YACrD,OAAO,MAAM,IAAIC,QAAQ,OAAOC,UAAY;gBAC1C,2FAA2F;gBAC3F,IAAInB,OAAOgB,gBAAgB,IAAI;oBAC7BhB,OAAOQ,cAAc,IAAI;oBACzBW;gBACF,OAAO;oBACLnB,OAAOW,OAAO,CAACS,IAAI,CAACD;oBACpB,MAAMnB,OAAOqB,cAAc;gBAC7B,CAAC;YACH;QACF;QAEAA,gBAAgB,iBAAkB;YAChC,qEAAqE;YACrE,IAAIrB,OAAOU,UAAU,EAAE;YAEvB,gDAAgD;YAChDV,OAAOU,UAAU,GAAG,IAAI;YAExB,MAAOV,OAAOW,OAAO,CAACW,MAAM,GAAG,EAAG;gBAChCzB,OAAO0B,IAAI,CAAC,CAAC,6DAA6D,EAAEvB,OAAOW,OAAO,CAACW,MAAM,CAAC,8BAA8B,EAAEE,KAAKC,SAAS,CAACzB,QAAQ,CAAC;gBAE1J,IAAI,CAACA,OAAOgB,gBAAgB,MAAMhB,OAAOK,OAAO,KAAKQ,WAAW;oBAC9DhB,OAAO6B,IAAI,CAAC,CAAC,0FAA0F,EAAE1B,OAAOW,OAAO,CAACW,MAAM,CAAC,mBAAmB,EAAEE,KAAKC,SAAS,CAACzB,QAAQ,CAAC;oBAC5K,MAAMJ,MAAMI,OAAOK,OAAO,GAAGS,KAAKC,GAAG;gBACvC,CAAC;gBAEDf,OAAOQ,cAAc,IAAI;gBACzB,qCAAqC;gBACrCR,OAAOW,OAAO,CAACgB,KAAK;YACtB;YAEA,sEAAsE;YACtE3B,OAAOU,UAAU,GAAG,KAAK;QAC3B;QAEAkB,wBAAwB,SAAUC,IAAI,EAAEC,WAAW,EAAE;YACnD,+DAA+D;YAC/D9B,OAAOQ,cAAc,IAAI;YACzB,+DAA+D;YAC/D,IAAI,CAACR,OAAOO,aAAa,CAACwB,QAAQ,CAACF,OAAO;YAC1C,yCAAyC;YACzC,IAAIA,SAAS,OAAOC,aAAa;YAEjC,2BAA2B;YAC3B,IAAI9B,OAAOK,OAAO,KAAKQ,WAAW;gBAChCb,OAAOK,OAAO,GAAGS,KAAKC,GAAG,KAAKf,OAAOI,QAAQ;YAC/C,CAAC;YAEDJ,OAAOC,eAAe,IAAI;YAC1BJ,OAAO6B,IAAI,CAAC,CAAC,iFAAiF,EAAE1B,OAAOC,eAAe,CAAC,CAAC;QAC1H;IACF;IAEA,OAAOD;AACT,CAAC"}
|
package/dist/manager.d.ts.map
CHANGED
|
@@ -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;
|
|
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,CAwqChF"}
|
package/dist/manager.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/restrict-template-expressions */ /* eslint-disable no-const-assign */ import {
|
|
2
|
-
import { calculateBits, camelize, camelToSnakeCase, delay, getBotIdFromToken, 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';
|
|
6
5
|
import { createRoutes } from './routes.js';
|
|
7
6
|
// TODO: make dynamic based on package.json file
|
|
8
7
|
const version = '19.0.0-alpha.1';
|
|
@@ -56,20 +55,27 @@ export function createRestManager(options) {
|
|
|
56
55
|
}
|
|
57
56
|
const newObj = {};
|
|
58
57
|
for (const key of Object.keys(obj)){
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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] = typeof value === 'string' ? value : calculateBits(value);
|
|
66
|
+
continue;
|
|
67
|
+
case 'defaultMemberPermissions':
|
|
68
|
+
newObj.default_member_permissions = typeof value === 'string' ? value : 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
|
+
}
|
|
67
77
|
}
|
|
68
|
-
|
|
69
|
-
newObj.default_member_permissions = calculateBits(obj[key]);
|
|
70
|
-
continue;
|
|
71
|
-
}
|
|
72
|
-
newObj[camelToSnakeCase(key)] = rest.changeToDiscordFormat(obj[key]);
|
|
78
|
+
newObj[camelToSnakeCase(key)] = rest.changeToDiscordFormat(value);
|
|
73
79
|
}
|
|
74
80
|
return newObj;
|
|
75
81
|
}
|
|
@@ -80,7 +86,7 @@ export function createRestManager(options) {
|
|
|
80
86
|
const headers = {
|
|
81
87
|
'user-agent': `DiscordBot (https://github.com/discordeno/discordeno, v${version})`
|
|
82
88
|
};
|
|
83
|
-
if (options?.unauthorized !==
|
|
89
|
+
if (options?.unauthorized !== true) headers.authorization = `Bot ${rest.token}`;
|
|
84
90
|
// IF A REASON IS PROVIDED ENCODE IT IN HEADERS
|
|
85
91
|
if (options?.reason !== undefined) {
|
|
86
92
|
headers[AUDIT_LOG_REASON_HEADER] = encodeURIComponent(options?.reason);
|
|
@@ -94,10 +100,11 @@ export function createRestManager(options) {
|
|
|
94
100
|
for(let i = 0; i < options.files.length; ++i){
|
|
95
101
|
form.append(`file${i}`, options.files[i].blob, options.files[i].name);
|
|
96
102
|
}
|
|
97
|
-
|
|
103
|
+
// Have to use changeToDiscordFormat or else JSON.stringify may throw an error for the presence of BigInt(s) in the json
|
|
104
|
+
form.append('payload_json', JSON.stringify(rest.changeToDiscordFormat({
|
|
98
105
|
...options.body,
|
|
99
106
|
files: undefined
|
|
100
|
-
}));
|
|
107
|
+
})));
|
|
101
108
|
body = form;
|
|
102
109
|
// No need to set the `content-type` header since `fetch` does that automatically for us when we use a `FormData` object.
|
|
103
110
|
} else if (options?.body !== undefined) {
|
|
@@ -219,8 +226,20 @@ export function createRestManager(options) {
|
|
|
219
226
|
authorization: 'Bot tokenhere'
|
|
220
227
|
}
|
|
221
228
|
});
|
|
222
|
-
const response = await fetch(url, payload)
|
|
229
|
+
const response = await fetch(url, payload).catch(async (error)=>{
|
|
230
|
+
logger.error(error);
|
|
231
|
+
// Mark request and completed
|
|
232
|
+
rest.invalidBucket.handleCompletedRequest(999, false);
|
|
233
|
+
options.reject({
|
|
234
|
+
ok: false,
|
|
235
|
+
status: 999,
|
|
236
|
+
error: 'Possible network or request shape issue occurred. If this is rare, its a network glitch. If it occurs a lot something is wrong.'
|
|
237
|
+
});
|
|
238
|
+
throw error;
|
|
239
|
+
});
|
|
223
240
|
logger.debug(`request fetched from ${url} with status ${response.status} & ${response.statusText}`);
|
|
241
|
+
// Mark request and completed
|
|
242
|
+
rest.invalidBucket.handleCompletedRequest(response.status, response.headers.get(RATE_LIMIT_SCOPE_HEADER) === 'shared');
|
|
224
243
|
// Set the bucket id if it was available on the headers
|
|
225
244
|
const bucketId = rest.processHeaders(rest.simplifyUrl(options.route, options.method), response.headers);
|
|
226
245
|
if (bucketId) options.bucketId = bucketId;
|
|
@@ -247,8 +266,6 @@ export function createRestManager(options) {
|
|
|
247
266
|
return;
|
|
248
267
|
}
|
|
249
268
|
options.retryCount += 1;
|
|
250
|
-
// Rate limited, add back to queue
|
|
251
|
-
rest.invalidBucket.handleCompletedRequest(response.status, response.headers.get(RATE_LIMIT_SCOPE_HEADER) === 'shared');
|
|
252
269
|
const resetAfter = response.headers.get(RATE_LIMIT_RESET_AFTER_HEADER);
|
|
253
270
|
if (resetAfter) await delay(Number(resetAfter) * 1000);
|
|
254
271
|
// process the response to prevent mem leak
|
|
@@ -675,7 +692,8 @@ export function createRestManager(options) {
|
|
|
675
692
|
},
|
|
676
693
|
async editMessage (channelId, messageId, body) {
|
|
677
694
|
return await rest.patch(rest.routes.channels.message(channelId, messageId), {
|
|
678
|
-
body
|
|
695
|
+
body,
|
|
696
|
+
files: body.files
|
|
679
697
|
});
|
|
680
698
|
},
|
|
681
699
|
async editOriginalInteractionResponse (token, body) {
|
|
@@ -1088,6 +1106,25 @@ export function createRestManager(options) {
|
|
|
1088
1106
|
return await rest.put(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), {
|
|
1089
1107
|
body
|
|
1090
1108
|
});
|
|
1109
|
+
},
|
|
1110
|
+
preferSnakeCase (enabled) {
|
|
1111
|
+
const camelizer = enabled ? (x)=>x : camelize;
|
|
1112
|
+
rest.get = async (url, options)=>{
|
|
1113
|
+
return camelizer(await rest.makeRequest('GET', url, options));
|
|
1114
|
+
};
|
|
1115
|
+
rest.post = async (url, options)=>{
|
|
1116
|
+
return camelizer(await rest.makeRequest('POST', url, options));
|
|
1117
|
+
};
|
|
1118
|
+
rest.delete = async (url, options)=>{
|
|
1119
|
+
camelizer(await rest.makeRequest('DELETE', url, options));
|
|
1120
|
+
};
|
|
1121
|
+
rest.patch = async (url, options)=>{
|
|
1122
|
+
return camelizer(await rest.makeRequest('PATCH', url, options));
|
|
1123
|
+
};
|
|
1124
|
+
rest.put = async (url, options)=>{
|
|
1125
|
+
return camelizer(await rest.makeRequest('PUT', url, options));
|
|
1126
|
+
};
|
|
1127
|
+
return rest;
|
|
1091
1128
|
}
|
|
1092
1129
|
};
|
|
1093
1130
|
return rest;
|